I have a scenario in which I have to mock a method in parent class. The method is invoked from the method under test. I have not been able to mock the function using jMockit.
My super class is method is as follows
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
// Email recipients code. I want to mock this function.
}
}
My subclass is as follows
public class MyClass extends SuperClass {
public void methodUnderTest(HttpServletRequest request) {
// Some code here.
List<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
I have tried using partial mocks using jMockit's tutorial, but it has not worked for me. My test method is given below.
UPDATE: I implemented Rogerio's suggestion as follows. The implementation still calls the real method. When I debug the instance of mocked class in Eclipse, this is what I see com.project.web.mvc.$Subclass_superClass#6b38c54e
#Test
public void testMethodUnderTest(#Mocked final SuperClass superClass) throws Exception {
final MyClass myClass = new MyClass();
new Expectations(myClass) {{
// .. Other expectations here
superClass.emailRecipients((List<String>) any);
}};
MockHttpServletRequest req = new MockHttpServletRequest();
myClass.methodUnderTest(req);
}
The issue is that when I try to mock the invocation of emailRecipients, it always tries to call the actual function. I am using Java 7, jMockit v1.35, and Maven 3x for our builds.
UPDATE The code is legacy code. As a result, we can't update it. We can not use PowerMock as it is not among the libraries that have been approved by the company. We can use either jMockit or Mockito or a combination of both.
The fact that you want to mock the method from parent class shows that your approach fails the Separation of Concerns/Single responsibility Pattern (SoC/SRP).
The use of PowerMock as suggested by Rajiv Kapoor is possible but this (as any use of PowerMock) would be a surrender to bad design.
You can solve your design problem by applying the Favor Composition over Inheritance principle (FCoI).
To do so you'd change your (most likely) abstract super class into a "normal" class. You'd create an interface that declares all the public and abstract methods in your super class. Your child class would no longer extend the parent class but implement the interface. It would get an instance of the former parent class as dependency and call it's methods providing common behavior as needed.
This dependency can easily mocked without the need of PowerMock.
UPDATE The code is legacy code. As a result, we can't update it.
In that case you are outruled.
The code you have is not unittestable because it is written in an untestable way. Your only chance is to write module and/or acceptance tests (without the use of a mocking framework) covering each and every execution path through your code.
This test will be expensive to create and slow but they will gurad your when refactoring the code to something testable (== changable) later.
see below example
P.S. use Mockito.any(HttpServletRequest.class)instead of Mockito.any(ArrayList.class) for your code
Super Class
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
System.out.println("Emailed!");
}
}
MyClass
public class MyClass extends SuperClass {
public void methodUnderTest() {
// Some code here.
ArrayList<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
Test Class
public class TestCase {
MyClass myClass = Mockito.mock(MyClass.class, Mockito.CALLS_REAL_METHODS);
#Before
public void prepare() {
PowerMockito.doNothing().when(myClass).emailRecipients(Mockito.any(ArrayList.class));
/*PowerMockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Custom code");
return null;
}
}).when(myClass).emailRecipients(Mockito.any(ArrayList.class));*/
}
#Test
public void testMethodUnderTest() throws Exception {
myClass.methodUnderTest();
}
}
If you don't want the code in emailRecipients to execute then use doNothing()
else use doAnswer to execute some other code
Related
I have code similar to this
class Util{
public String transform(String str);
//lots of logic including ajax calls
return("Modified"+str);
}
public caseChange(String str){
//lots of logic including ajax calls
return str.toUpperCase()
}
class TextParser extends Util{
public String parse(str)
//lots of logic to modify str
str = caseChange(str);
//some more logic to modify str
return transform(str);
}
Is there anyway to mock the caseChange and transform methods to return some mocked data and prevent a call to the superclass when i call
String result = new TextParser().parse("hello")
in the unit test class to assert result.
The transform and changeCase are over simplified in my example. In reality they perform ajax calls and there is a ton of other logic. I want to mock them out so that can unit test just this part an then unit test the super methods later
You may need to create another subclass like
class TextParserForTest extends TextParser {
#Override
public String parse(String str) {
super.parse(str);
}
#Override
public String caseChange(String str) {
return "whatever";
}
}
edit : use mockito to this :
import static org.mockito.Mockito.*;
import org.junit.Test;
#Test
public void test() {
TextParser tp = mock(TextParser.class);
// all the methods that you want to test
when(tp.parse(any())).thenCallRealMethod();
when...
// all the methods that you want to mock
when(tp.caseChange(any()).thenReturn("whatever");
when...
}
In your given example: you simply don't do that. Your methods are only working on your inputs; so it should absolutely not matter where those methods are implemented.
In other words: it seems most appropriate for you to focus on contract checking tests only. Like:
#Test
public testWhatever() {
assertThat(new TextParser.parse("hello"), is("expected output"));
}
Yes, you can probably mock such things using Mockito/Powermock; but you shouldn't! You see, your production code is directly calling those methods; so you want to test that calling parse gives you expected results (while using all the code that will also run in a production setup!)
Edit: given your comment about that methods being "complicated". Then I suggest: do not use inheritance here. You should not make class B a subclass of A just to have easy access to some methods. In other words: inheritance is about modeling an IS-A relation. So, a TextParser is a Util? Doesn't sound very convincing.
Thus: you better turn to composition here. Your TextParser should use a Util object. And that one can be provided via dependency injection; and your need to mock with inherited methods vanishes completely!
You can use the spy functionality of Mockito. The spy calls real methods unless they are stubbed.
#Test
public void testParse() {
TextParser textParser = Mockito.spy(new TextParser());
when(textParser.caseChange(Matchers.anyString())).thenReturn("mocked");
Assert.assertEquals("Modifiedmocked", textParser.parse("hello"));
}
I'm running through some service tests and I am testing a concrete class that extends from one that uses generics.
An example setup of the service layer is below:
public abstract class AbstractService <E extends AbstractEntity, IT extends AbstractItem> {
public void deleteAllItems(E entity) {
List<IT> items = new ArrayList<IT>(entity.getItems());
for(IT item : items) {
//Yada, yada
}
}
}
public class Service extends AbstractService<Entity, Item> {
}
public class OtherService() {
#Inject
private ServiceManager serviceManager;
public void deleteItems(Entity e) {
serviceManager.getService().deleteAllItems(e);
}
}
Then to test it I have the following:
public class Test {
private Service service;
private OtherService otherService;
private ServiceManager serviceManager;
#BeforeMethod
public void setup() {
serviceManager= mock(serviceManager.class);
service= mock(Service.class);
when(serviceManager.getService()).thenReturn(service);
otherService=injector.getInstance(OtherService.class);
}
#Test
public void test() {
Entity e = new Entity();
//Attach some items
otherService.deleteItems(e);
verify(service).deleteAllItems(e);
}
}
This should call the OtherService, which exists (We're using injection to get ahold of the object), and then call the method deleteItems(), which in turn should call deleteAllItems() on the Service. Before I had implemented the Java generics, this worked fine, but since I have implemented the Java generics, the Mockito test fails with the following exception:
java.lang.NoSuchMethodError:
Service.deleteAllItems(Entity;)V
at
Test.test(Test.java:XXX)
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at Test.test(Test.java:XXX)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of:
final/private/equals()/hashCode() methods. Those methods cannot be
stubbed/verified.
Which sounds like it can't find the method. Should I instead mock the abstract class of AbstractService or is there something else that I am missing?
EDIT
From what I've seen of the Mockito inner workings, it creates an instance of this:
public void AbstractService.deleteAllItems(Entity)
For the MockitoMethod object, so that would make sense that Service.deleteAllItems() "isn't called", it appears Mockito assumes only the baseclass was ever called. So it does appear that I need to mock the base class instead. I'm going to investigate further, but if anyone has any other ideas, I'm open to suggestions
I can suggest to localize the problem - either it is in mocking:
#Test
public void test() {
Entity e = new Entity();
service.deleteItems(e); // Note! 'service' itself, not an 'otherService'
verify(service).deleteAllItems(e);
}
or in injection (remove inheritance and generics):
public class Service /*extends AbstractService<Entity, Item>*/ {
public void deleteAllItems(Entity entity) {
//...
}
}
Split the problem iterativelly and you will find the cause.
When you create a non-generic subclass of a generic class, Java creates "bridge methods" for any methods that use the generic type. The bridge methods look like the inherited methods but use the the specific class specified for the generic parameters instead of generics.
Java creates these methods because the methods of the subclass are not generic, so they need to "look like" non-generic methods (i.e. not subject to erasure, reflection will work as expected, etc). See this answer for details.
The solution is to have Mockito mock the type returned by serviceManager.getService().
After further investigation, I found a way to force Mockito to call the correct class. As I mentioned briefly, we're using injection to get ahold of the object. During the setup we do run through a setup of the injector, which I hadn't felt was causing the issue. But it did present a solution. This was how we were calling it:
Injector injector = Guice.createInjector(new Module() {
#Override
public void configure(Binder binder) {
service = mock(Service.class);
binder.bind(Service.class).
toInstance(service);
}
To solve the issue, we just bound the AbstractService class to the mocked instance of the Service class, like so:
Injector injector = Guice.createInjector(new Module() {
#Override
public void configure(Binder binder) {
service = mock(Service.class);
binder.bind(Service.class).
toInstance(service);
binder.bind(AbstractService.class).
toInstance(service);
}
So now, when Mockito attempts to get an instance of the AbstractService, it calls the mocked Service and solves our issue.
If anyone has any feedback it there is an alternative solution, then feel free to post and I can test it out and check if there are better methods that what we are doing.
I want to make a JUnit test to assure that some classes don't use a specific set of methods (from another classes). Example
class MyClass
{
void myMethod()
{
otherClass.otherClassStaticMethod();
}
}
class myTest
{
void test()
{
assertFalse(CalledMethods.getMethodsCalledBy("myClass.myMethod").Contains("otherClass.otherClassStaticMethod"));
}
}
In this test I want to assure that myMethod doesn't invocate otherClassStaticMethod. How can I find what methods are being called inside a method in compile time (ignore methods called using reflection)? I thought about a .java parser, do you recommend any?
you can mock "otherClass" and verify that the method isn't invoked. E.g. using Mockito you can even specify in which order what methods are supposed to be invoked (under the condition their instances are mocks) and specify which methods are not allowed to be invoked
as coding.mof said, to mock static methods you should use PowerMock/PowerMockito:
example:
PowerMockito.mockStatic(OtherClass.class);
PowerMockito.verifyStatic(never());
OtherClass.otherClassStaticMethod();
It sounds like you should be using a mock library and let that handle it all for you. I'd recommend JMock as my library of choice. If you're using instance methods then this would be perfect for you - if, as your example shows, it's static methods then PowerMock may work*1.
With JMock, you'd have something like:
public class MyClass {
public MyClass(Dependency dependency) {
this.dependency = dependency;
}
void myMethod() {
dependency.someMethod();
}
}
#RunWith(JMock.class)
public class MyTest {
private Mockery context = new Mockery();
#Test
public void doesNotCallSomeMethod() {
Dependency dependency = context.mock(Dependency.class);
MyClass obj = new MyClass(dependency);
obj.myMethod(); <--- this will fail fast
}
}
When you call obj.myMethod, JMock will instantly report that you never said dependency should have any methods called. It will also tell you what method you DID call and what parameters you passed in if any
*1 I don't use PowerMock as I steer away from static methods unless they are pure functions
Is it possible using Mockito and optionally Powermock to mock a superclass S such that any calls to the superclass to S (including calls to the S() constructor) are mocked? So using the below example, if I replace S with MockS using Mockito, will the call to super() use the constructor in MockS?
class S {
S() {
// Format user's hard drive, call 911, and initiate self-destruct
}
}
class T extends S {
T() {
super();
}
}
class Test {
#Mock private S mockS;
new T(); // T's call to super() should call the mock, not the destructive S.
}
I've seen questions about mocking individual methods in S or mocking only calls to super(), and read that this is unsupported, but it's not clear whether or not I can mock the entire superclass.
With my current tests, when I try to mock S, T's call to super() calls the real implementation, not the mock.
To work around this apparent limitation, I refactored my code, replacing inheritance with delegation, and I think I've ended up with a better design anyhow since the inheritance wasn't really necessary.
The new code looks like this. Mind you the code for the question was simplified, so the real classes have much more functionality.
class S {
S() {
// Format user's hard drive, call 911, and initiate self-destruct
}
}
class T {
T(S s) {} // Now T "has an S" instead of "is an S"
}
class Test {
#Mock private S mockS;
new T(s); // T's call to super() should call the mock, not the destructive S.
}
For those interested, using Guice and Android, the test looks more like this:
class T {
T(Activity activity, S s) {}
}
class Test {
#Mock Activity activity;
#Mock S mockS;
injector = Guice.createInjector(new AbstractModule() {
#Override protected void configure() {
bind(Activity.class).toInstance(activity);
bind(S.class).toInstance(mockS);
}}
);
T t = injector.getInstance(T.class);
}
I think this is possible with PowerMock only if the method on the child is different from the method on the superclass (i.e., you cannot mock the parent method if the child overrides that method). For a little more detail, you can look at the relevant bug report.
For PowerMock, check out Suppressing Unwanted Behavior page to see if it will be enough for your needs.
After much digging around, I ended up using JMockit for these tricky cases. Before I moved on to JMockit, I tried stubbing out all the places exceptions were thrown using suppression. In the end, I needed to override some methods, and not just suppress them, so I ended up abandoning it.
Example usage for Android case:
First, you mock out your superclass using the #MockClass annotation:
#MockClass(realClass = Activity.class, instantiation = PerMockedInstance)
public class FakeActivity {
public Bundle mSavedInstanceState;
#Mock
public void $init() {}
#Mock
public void onCreate(Bundle savedInstanceState) {
mSavedInstanceState = savedInstanceState;
}
}
When activated, this class will replace the default constructor of Activity with $init(), and replace the onCreate method with the one above. WIth android, the unit under test is derived from Activity (in my sample code, it is HelloTestActivity). The test class looks like this:
public class HelloTestActivityTest3 extends AndroidTest {
#Tested
HelloTestActivity activity;
FakeActivity fakeActivity = new FakeActivity();
#Before
public void setupMocks()
{
Mockit.setUpMock(fakeActivity);
}
#Test
public void onCreate_bundle(#Mocked Bundle savedInstanceState)
{
// Try to access out-of-band information from the fake
activity.onCreate(savedInstanceState);
assertSame(savedInstanceState, fakeActivity.mSavedInstanceState);
}
}
The call Mockit.setupMock(fakeActivity) replaces the super class with my instance of the fake. With this usage, you can access internal state of your fake class as well. If you don't need to override any methods with custom functionality, you can use other methods available from Mockit class.
As rogerio pointed out in the comments below, mocking the Activity class is the bare minimum. The following code demonstrates this.
public class HelloTestActivityTest4 {
#Tested
HelloTestActivity activity;
#Mocked
Activity base;
#Test
public void testOnCreate() throws Exception {
// Just make sure "Stub!" exception is not thrown.
activity.onCreate(null);
}
}
The declaration #Mocked Activity base; causes all methods (excepting static initializers) of Activity class and its superclasses to be mocked in the tests defined in HelloActivityTest4.
What you can do is extract the 'dangerous' code in your superclass constructor into a non-private method, then use Mockito spy on your class T and override the behaviour in that extracted method.
This would of course violate encapsulation. Guava offers the VisibleForTesting annotation for such cases.
Referred this question first. But seems my context is different.
I'll try to be short and simple. (Just the code I'm putting out is quite big ;)
I have some 50+ service classes. And need to write the unit test cases for all of them.
Across all these test classes, some tests are common. (delete, find etc) Just the object type would differ across the service classes.
Following example would clear the picture.
Consider following service class which has CRUD operations.
public class ObjService {
public Obj addObj(ParamType param, String var) { ... }
public void deleteObj(ParamType param, String var) { ... }
public List<Obj> findAllObj(ParamType param, String var) { ... }
public Obj findById(ParamType param, String var, String objIdToFind) { .. }
public List<Obj> getAllObjs(ParamType param, String var, ObjQuery objQuery) throws Exception { ... }
public Obj updateObj(ParamType param,
String var, Obj objToUpdate) throws Exception { }
}
Now I'm writing a test case for ObjService class. (Test Framework - testNG)
public class ObjServiceTest {
//These methods which will differ across all service classes
#Test
public void testAddObj() throws Exception {
addObj();
}
#Test
public void testUpdateObj() throws Exception {
Obj objToUpdate = addObj();
Obj updatedObj = updateObj(objToUpdate);
}
public Obj addObj() throws Exception {
//add obj test data and return the obj object
}
public Obj updateObj(Obj objToUpdate) throws Exception {
//update obj test data and return the updated obj object
}
//Following methods will be common to all classes. Except the name 'obj'
//e.g. For obj2 it would change to testDeleteObj2() { Obj2 obj2Todelete.... etc}
#Test
public void testDeleteObj() throws Exception {
Obj objToDelete = addObj();
deleteObj(objToDelete);
}
public void deleteObj(Obj objToDelete) throws Exception {
//delete the obj object
}
#Test
public void testFindById() throws Exception {
ObjService client = new ObjService();
List<Obj> objs = dsClient.findAllObj(...);
}
#Test
public void testFindAllObjs() throws Exception {}
#Test
public void testGetObjs() throws Exception {}
}
Now. Writing the common methods manually for all classes is surely a time consuming job. So can it be reduced by doing some automation?
(Tried my best to put the question in least baffling way)
Edit: 1) The test classes already inherit a BaseTestClass which contains the initial setup needed. So that is a problem.
2) Please don't forget the part, where
refactoring is needed across the
methods which differ.
It sounds like your services should implement some generic interface. That way you could write an abstract base test case which is also generic, then make each "real" service test inherit from it, including inheriting the tests within that abstract class.
The constructor for the subclass would pass in the appropriate values for things like the service, a sample query etc.
EDIT: For the base class, just make the abstract base test class subclass your existing base class.
For specialization, either override the test method itself when it needs to do a completely different thing, or make the test methods depend on abstract methods in the abstract class, so that each concrete subclass can fill in the appropriate behaviour.
A good first step would be to make a base Test class which handles the common methods, and then derive specific Test classes from that base class to test the methods which differ per service.
You could make the base Test class a generic class which takes your service objects as a generic parameter. You may want or need to make your service classes implement a common interface, so that you can test the common methods in a consistent, type-safe manner.
Create an abstract class that contains all tests that are common to all Services.
Include abstract method definitions for the methods that have to be implemented differently in each test class.
Now create all your test classes as subclass of this abstract class, implementing only what's needed for the individual Service.
One possible solution could be to genericize your test cases with the object type as generic type parameter. Possibly having a generic base test class, and instantiating it with the needed concrete type(s) in each separate test subclass. I did it in a somewhat similar case and it worked out well.
Eventually, if you have much duplicated functionality to test, consider refactoring your tested classes (possibly using generics as well) to eliminate duplication. However, write the unit tests first to ensure that you aren't breaking anything during the refactoring.