I have a method in my MainActivity (Android) and I want to mock the A instance :
public void some_method() {
A a = new A();
....
}
so I created a kind of factory class as such
public class SomeFactory(){
// some constructor
public A populateWithParameter(Parameter parameter){
return new A(parameter)
}
}
and the method above turns into
public void some_method(SomeFactory someFactory) {
A a = someFactory.populateWithParameter(parameter);
a.method_call()
....
}
I tried this
#Mock
SomeFactory someFactory;
public void testSomeMethod() throws Exception {
SomeFactory someFactory = new SomeFactory();
when(someFactory.populateWithParameter(
some_parameter)).thenReturn(null);
mainActivity.some_method(someFactory);
...
}
but I get this error message
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
You are not mocking your factory. Also, wrong method call.
Do this instead.
SomeFactory someFactory = mock(SomeFactory.class)
when(someFactory.populateWithParameter(
some_parameter)).thenReturn(null);
mainActivity.some_method(someFactory);
UPDATE
Your code has changed so for completeness this is what your test should look like. In the updated code above, you were overwriting your mock with a real object. Assuming your objects are correctly set up. Notice the different syntax for providing a return object. I think this is more readable.
#Mock SomeFactory mockFactory;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this); // set up annotated mocks
}
#Test
public void testSomeMethod() {
A subject = new A();
doReturn(subject).when(mockFactory)
.populateWithParameter(any(Parameter.class));
main_activity.some_method(mockFactory);
verify(mockFactory,times(1)).populateWithParameter(any(Parameter.class));
}
Best Practices
When naming methods and variables, use camelCase. So main_activity becomes MainActivity, some_method becomes SomeMethod.
You need a way to overwrite the instance of A from your test. Typically this is done using an injection framework. For a simple case, you can make the field under test protected (assuming the test class is in the same package as the class under test).
The error you are seeing comes interacting with a "real" object as if it was a mock.
In this case SomeFactory is a real object so it cannot be when()ed
From the point of view of response of #DiscoS2, there is indeed an issue with this declaration
MockitoAnnotations.initMocks(this);
You should use instead SomeFactory someFactory = mock(SomeFactory.class) and then follow the updated response of #DiscoS2
Related
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
I have to deal with a legacy application that has no tests. So before I begin refactoring I want to make sure everything works as it is.
Now imagine the following situation:
public SomeObject doSomething(final OtherObject x, final String something) {
if(x != null) {
final String = someOtherMethod(x, something);
}
}
protected String someOtherMethod(final OtherObject x, final String something) {
....
}
Now I want to make sure that protected method is called as well
So I did this
#InjectMocks // Yes there is more going on here
private MyTestObject myTestObject;
private MyTestObject spy;
private static final OtherObject VALID_OTHER_OBJECT = new OtherObject();
#Before
public void setup() {
this.spy = Mockito.spy(myTestObject);
}
#Test
public void ifOtherObjectIsNotNullExpectSubMethodToBeCalled() {
myTestObject.doSomething(VALID_OTHER_OBJECT, null);
verify(spy).someOtherMethod(VALID_OTHER_OBJECT, null);
}
I get a failing test and "Wanted but not invoked..." for someOtherMethod().
I jumped right into debug mode and checked. That method is called!
What could be the cause of this? Am I misusing the spy here?
Edit: I want to stretch that I know this is not what you typically test for, especially since someOtherMethod(...) has a non-void return-value here. But imagine the return value was void...
Basically I just want to understand why the spy fails here.
As per its Javadoc, Mockito.spy(object) creates a copy of the passed in object. Calling methods on the original passed in object then does not register on the spy, because the spy instance is not the same object.
Change myTestObject.doSomething(...) to spy.doSomething(...) and it should work.
Alternative (different way to achieve the same thing):
Consider using the #Spy annotation on your myTestObject.
Be sure to add MockitoAnnotations.initMocks(this); to your initialization method (in your junit test).
The #Before and #Mock annotations are useful as well.
I had one object creating another and that other object making calls. So I needed to make that internal object be using the spied reference instead. I used reflection and updated the reference using Whitebox.
TestAddressFragment fragment = spy(new TestAddressFragment());
AddressPresenter presenter = fragment.getPresenter();
Whitebox.setInternalState(presenter, "view", fragment );
Now my fragment could check if its method was called.
verify( fragment ).showAddress(any(), anyBoolean());
I have a void method that does something. I do not care what it does in my unit test class. However, it is throwing exception when I call it from my unit-test class and it is causing my test cases to fail.
How can I, using EasyMock, mock this object so that when this void method gets called, I ignore what it does in my unit test?
For example, let's say the object is called myObject and it has a void method called doSomething().
EasyMock doesn't let me use 'expect' because it is a void method that returns nothing. But when I call this method in my test case, it throws an exception (which I want to completely ignore).
I know this can be achieved by maybe using mockito or other libs, but I'd like to use EasyMock.
UPDATE
the method in question is a private void method which gets called by other processes. i cannot call it directly but i still want to ignore the exception that's thrown by that private void method.
i've tried using nice mock as suggested as below.
MyObject obj = EasyMock.createNiceMock(MyObject.class);
EasyMock.replay(obj);
and then i set this obj in another object that contains it as private variable.
MyObject2 obj2 = new MyObject2();
obj2.setMyObject(obj);
and i call some method that calls the private void method internally.
obj2.methodThatCallsPrivateVoidMethod();
and this did not work.
Without using EasyMock, a common approach to this is to override the problematic method in a testable version of your class.
Assuming this is your class
class MyClass {
...
public void doSomething() {
...
}
}
Do this in your test:
public class MyTestClass {
#Test
public void testThis {
MyClass myObject = new TestableMyClass();
...
// Now you can invoke methods on myObject and the
// doSomething() method will be harmless.
}
class TestableMyClass extends MyClass {
#Override
public void doSomething {
// Do nothing. Thus no exception.
}
}
}
Note that EasyMock may provide a similar way to do this, but I am not familiar with EasyMock. I know that this is not a problem with Mockito.
I want to write a unit test for a service that uses/depends on another class. What i'd like to do is mock the behavior of the dependent class (As opposed to an instance of that class). The service method being tested uses the dependent class internally (i.e. an instance of the dependent class isn't passed in to the method call) So for example I have a service method that I want to test:
import DependentClass;
public class Service {
public void method() {
DependentClass object = new DependentClass();
object.someMethod();
}
}
And in my unit test of Service method(), I want to mock someMethod() on the DependentClass instance instead of having it use the real one. How do I go about setting that up in the unit test?
All of the examples and tutorials i've seen show mocking object instances that are passed in to the method being tested, but I haven't seen anything showing how to mock a class as opposed to an object instance.
Is that possible with Mockito (Surely it is)?
It's easy with Powermockito framework and whenNew(...) method. Example for your test as follows:
#Test
public void testMethod() throws Exception {
DependentClass dependentClass = PowerMockito.mock(DependentClass.class);
PowerMockito.whenNew(DependentClass.class).withNoArguments().thenReturn(dependentClass);
Service service = new Service();
service.method();
}
Hope it helps
This is a problem of poor design. You can always take in the param from a package private constructor.
Your code should be doing something like this:
public class Service {
DependentClass object;
public Service(){
this.object = new DependentClass();
}
Service(DependentClass object){ // use your mock implentation here. Note this is package private only.
object = object;
}
public void method() {
object.someMethod();
}
}
I want to use pattern 1 suggested in the following link:
https://code.google.com/p/mockito/wiki/MockingObjectCreation
and have the following class:
public class MyClass {
private AnyType anyObject;
private Foo foo; // Foo is a thirdparty class
public MyClass(AnyType anyObject) {
//...
foo = makeFoo();
}
private Foo makeFoo() {
return new Foo();
}
}
I'm trying to make a test as follows:
#Test
public void myTestMethod() {
MyClass myClass = Mockito.spy(new MyClass());
// now i want to do something like this:
Foo mockFoo= Mockito.mock(Foo.class);
// Mockito.doReturn(mockFoo).when(myClass).makeFoo());
}
The problem is my factory method makeFoo is a private method, so I can't access it. I don't want to make it public just for the test. My test classes are not in the same package as my productive code either, so making it visible only for the package won't work.
Update:
Now i found another problem. Assumed that makeFoo() is public, 'mockFoo' will not be returned either, yet the real makeFoo() method is invoked. This happens since the invocation of makeFoo() (in the constructor of MyClass) is prior to the creation of mockFoo.
Does anyone know how to solve this problem or am I doing something totally wrongly?
Thanks you guys in advance for helping!!
Have a look at whenNew of PowerMockito. This allows to "overwrite" the constructor call of an object and return a mock of it instead.
http://powermock.googlecode.com/svn/docs/powermock-1.3.7/apidocs/org/powermock/api/mockito/PowerMockito.html#whenNew%28java.lang.Class%29
http://www.gitshah.com/2010/05/how-to-mock-constructors-using.html
If you just need to set a field inside your class, it's doable with MockitoAnnotations
You just need to create fields you need, annotate them and in unit test before section call MockitoAnnotations.initMocks(this)
In your case it will look like:
#Spy
#InjectMocks
MyClass myClass;
#Mock
Foo foo;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
Please read also documentation above.