How do I mock call method from testable class? - java

Want to ask you a question.
How should I properly return some data from method called from testable class ?
For example I have next structure:
Class SomeClass {
public void method1(){
//some logic here
List<Object> howToReturnHereValues = gatData();
//some logic here
}
public List<Object> getData(){
return List<Object>;
}
}
Right now I want to test method1(), but I don't know how to mock call getData() which returns List<Object>.
Any advice please ?

You can do this using a spy, like explained here: https://static.javadoc.io/org.mockito/mockito-core/2.7.17/org/mockito/Mockito.html#13
Example:
#Test
public void testMethod1() throws Exception {
SomeClass someClass = new SomeClass();
SomeClass spy = Mockito.spy(someClass);
Mockito.when(spy.getData()).thenReturn(Arrays.asList("blaat", "blabla"));
spy.method1();
}
This will return a List of "blaat" and "blabla" which can be used by the logic in your method1.

Right now I want to test method1(), but I don't know how to mock call
getData() which returns List.
It is rather a bad idea to mock a public method of a class that is under test.
A unit test should test a behavior and mock dependencies. Here, you unit test only a part of the behavior as you mock the behavior of the tested class.
If the class is ours you could :
either test this method without mocking the getData() called public method.
or move the getData() public method in another class and then mock this new dependency if you don't want to repeat the test of the getData() method in each test method calling it.
If the class is not modifiable and the mocked called is really required, you could use the spy() method of the Mockito framework on the object under test to simulate a mocked behavior for a specific method.

Related

Testing lazy initialization by j.u.f.Supplier with Mockito

I have a class Sut with lazy initialization implemented using java.util.function.Supplier. In fact it's more complicated that the code below, but this is the simplest form that Mockito cannot test. The test below throws an error Wanted but not invoked ... However, there were other interactions with this mock. Why doesn't Mockito count the invocation of create? The code flow actually enters create(); I checked that with debugger.
import java.util.function.Supplier;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class TestTimes {
#Test
public void testCreateOnlyOnce() {
Sut sut = spy(new Sut());
sut.getData();
sut.getData();
sut.getData();
verify(sut, times(1)).create();
}
private static class Sut {
Supplier<Object> data = this::create;
void getData() {
data.get();
}
Object create() {
return new Object();
}
}
}
First of all, thanks for the well written question.
I have tested your code myself and seen the error you mentioned. Although, I have changed your code a little bit while debugging... Take a look:
#Test
public void testCreateOnlyOnce() {
Sut sut = spy(new Sut());
sut.getData();
sut.getData();
sut.getData();
verify(sut, times(1)).create();
}
private static class Sut {
private Supplier<Object> data;
// Added de data object initialization on the constructor to help debugging.
public Sut() {
this.data = this::create;
}
void getData() {
data.get();
}
Object create() {
return new Object();
}
}
What I found out while debugging:
The Sut class constructor is being called correctly inside the spy(new Sut()) clause, but the create() method is not being called there.
Every time sut.getData() is called, the create() method is also called. What made me conclude, finally that:
On the constructor, all that this::create did was telling java that, whenever it needs to retrieve the Object from the supplier, that Object will be retrieved from the create() method. And, the create() method being called by the supplier is from a class instance different from what Mockito is spying.
That explains why you cannot track it with verify.
EDIT: From my research, that is actually the desired behavior of the Supplier. It just creates an interface that has a get() method that calls whatever noArgs method you declared on the method reference. Take a look at this on "Instantiate Supplier Using Method Reference".
I want to add a little to Gabriel Pimentas excellent answer. The reason why this works as it does is that mockito creates shallow copies of the spy new Sut() and your Supplier refers to the compiled lambda method inside the original Sut instance and not the spy instance.
See also this question and the mockito documentation.
When you debug your code, you can see how this works:
Sut sut = spy(new Sut()); is now a mocked/spied subclass of Sut as the instance TestTimes$Sut$MockitoMock$1381634547#5b202a3a. Now, all fields from the original new Sut() are shallow-copied, including the Supplier<Object> data. Looking at this field inside the spy, we can see that it is an instance of TestTimes$Sut$$Lambda$1/510109769#1ecee32c, i.e. pointing to a lambda inside the original Sut. When we set a breakpoint inside the create method, we can further observe that this points to TestTimes$Sut#232a7d73, i.e. the original Sut and not the spied instance.
EDIT: Even though this MCVE probably does not resemble your actual code, the following solutions come to mind:
Inject the Supplier into your Sut (either during construction or as a parameter to getData.
Create the supplier lazily within your getData method (so that it points to the mockito-instance)
Don't use a Supplier but just call create directly if the Supplier is not passed from the outside

Mockito NotaMockException

I am facing an issue with Mockito junit testing. I am new to it and am a bit confused with the problem I am facing. Any help on this would be appreciated.
class Activity{
public void firstMethod(){
String str = secondMethod();
}
public String secondMethod(){
String str = null;
/* some Code */
return str;
}
}
Getting exception :
*org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!*
in the below code
class ActivityTest(){
Activity act;
#Before
public void setup(){
act = new Activity();
}
#Test
public void testFirstMethod(){
Mockito.doReturn(Mockito.anyString()).when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
I am aware that activity is not a mock but I am not sure for a way around this as secondMethod() is a method in the same class. I need to write rule for secondMethod() as I have already done its Unit Testing. The definition of secondMethod() consists has external dependencies. Should I be mocking the external dependencies present in secondMethod() and writing rules for them rather than rule for secondMethod()?
I found this post:
Mockito Spy'ing on the object being unit tested
However separating the secondMethod() into a different class does not make sense. My method is related to this class. Creating a different class for testing does not seem right to me. Even mocking the actual class using spy() is not the most correct way as already explained in the post.
I don't think I should be creating a mock of the Activity class as that is the class I am testing. I would really appreciate help and insights into this.
As you noted, act is not a mock, and therefore you cannot record behavior on it. You could use Mockito.spy to, well, spy (or partially mock) the act object so that you only record the behavior of secondMethod and execute the actual code for firstMethod.
Note, however, that matchers can't be used in doReturn calls regardles of how you're mocking or spying your object. A return value must be a concrete object.
class ActivityTest() {
Activity act;
#Before
public void setup(){
act = Mockito.spy(new Activity()); // Here!
}
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
A slightly more elegant syntax allows you to use annotations instead of explicitly calling Mockito.spy, but it's a matter of taste really:
#RunWith(MockitoJUnitRunner.class)
class ActivityTest() {
#Spy
Activity act = new Activity();
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
There is no reason to mock anything in this example. Since there are no dependencies and both methods are public, you can test them directly.
public class ActivityTest() {
private Activity act = new Activity();
#Test
public void testSecondMethod(){
assertEquals("expected-value", act.secondMethod());
}
#Test
public void testFirstMethod() {
act.firstMethod();
// success if no exception occurs
}
}
Since firstMethod does not have any detectable effect on the Act instance, nor on any dependency (since there are none) you can simply call the method and be satisfied if no exception is thrown. One could also reason that such a method should not be tested at all.
I assume the example given is a simplification of a class where calling firstMethod actually does have side effects, who knows...
Here are some hints:
Mock the Activity.
Tweak the behavior of secondMethod with when / then / doReturn
Use doCallRealMethod when firstMethod is invoked.
Hope it helps.

Mocking a local object inside a method of SUT using Mockito or PowerMocktio

I've class method like below which creates a local object and calls a method on that local object.
public class MyClass {
public someReturn myMethod(){
MyOtherClass otherClassObject = new MyOtherClass();
boolean retBool = otherClassObject.otherClassMethod();
if(retBool){
// do something
}
}
}
public class MyClassTest {
#Test
public testMyMethod(){
MyClass myClassObj = new MyClass();
myClassObj.myMethod();
// please get me here..
}
}
When I'm testing myMethod, I want to mock otherClassObject.otherClassMethod to return something of my choice. otherClassMethod does some class to Message Queues and I don't want that in Unit test. So I want to return true when I do otherClassObj.otherClassMethod(). I know I must have used a factory for MyOtherClass instantiation in this case but it's legacy code and I don't want to change any code now. I see that Mockito doesn't provide this facility to mock MyOtherClass in this case but possible with PowerMockito. However, I could not find an example for above scenario but found only for static class. How should I mock local object inside a method of SUT ?
I also referred to some other OS questions like - Mocking methods of local scope objects with Mockito but they were not helpful.
A code example will be of great help.
If you are using PowerMockito you can use the whenNew method
It should look something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class) //tells powerMock we will modify MyClass to intercept calls to new somewhere inside it
public class MyClassTest{
#Test
public void test(){
MyOtherClass myMock = createMock(MyOtherClass.class);
//this will intercept calls to "new MyOtherClass()" in MyClass
whenNew( MyOtherClass.class).withNoArguments().thenReturn( myMock) );
... rest of test goes here
}
Also this other SO post has example code too PowerMockito Mocking whenNew Not taking affect
OK, this is not a real answer but with PowerMockito you can do this:
final MyOtherClass myOtherClass = mock(MyOtherClass.class);
// mock the results of myOtherClass.otherClassMethod();
PowerMockito.whenNew(MyOtherClass.class).withNoArguments()
.thenReturn(myOtherClass);
// continue with your mock here
Now, not sure whether you actually need the result of this otherClassMethod here, but if you don't, I'd suggest you mock the results of myMethod() instead -- unless myMethod() is what you want to test because this other method has an influence on it, and yes, in this case a refactoring should be considered... And not delayed ad vitam aeternam...

Unit Testing Java Code - Mocking a non-static method of a different class

public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
Here I want to test the method "doSecond()" of class "First". For the same, I want to mock the method "doJob" of class "Second".
I know that I can create a mocked instance of class "Second" using the code below.
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
But I cannot relate this mocked instance with class "First" as of the current code.
Without refactoring the source code, is there any way by which i can achieve the requirement.
Please help.
Take a look at powermock's ability to intercept calls to new and return mocks instead
https://code.google.com/p/powermock/wiki/MockConstructor
This doesn't require changing any sourcecode.
here's the test code where we actually return a mock when First.doSecond() calls new Second()
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class TestFirst {
#Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
It's tricky to mock an instance that you create inside of a method, but it's possible.
Using PowerMock, you can accomplish this with the PowerMock.expectNew() method:
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class StackOverflowTest {
#Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
Effectively, PowerMock is proxying the creation of the new object and substituting whatever value we want when we invoke doSecond().
So, it's possible. However, this is a terrible practice to get into.
One typically wants to mock objects if they involve an outside concern, such as another layer (i.e. database, validation), or if the desired output is coming from other objects that are injected but are safe enough to consider tested.
If your method is capable of getting or retrieving data from a non-injectable source, you should not want to mock that out.
Considering that your method is simple and straightforward, you should really not need to do any mocks here at all. But if you felt that you were forced to, you could do one of a few things:
Create a factory for the creation of Second, and mock the results of the returning factory object with Mockito.
Pass in an instance of Second to that method, and use Mockito as the mock instance.
Declare it as a field (i.e. injected dependency), and use Mockito.
For completeness, here is how the test can be written with the JMockit mocking API, without any refactoring of the original code under test:
public class ExampleTest
{
#Test
public void firstShouldCallSecond(#Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}

How to mock local variable obtained from another method of tested class?

I have following class
class MyClass{
public void m(InputStream is){
...
Parser eParser = getExcelFileParser();
eParser.parse(is);
...
eParser.foo();
eParser.bar();
}
public ExcelFileParser getExcelFileParser(){
...
}
}
How to write unit test for method m at this situation? I want to mock eParser object only.
Is it possible?
I use Mockito and PowerMockito
You can do what you want in Mockito (no PowerMock needed) using a spy without changing your code at all.
In your unit test you need to do something like the following:
ExcelFileParser parser = mock(ExcelFileParser.class);
MyClass myClass = spy(new MyClass());
doReturn(parser).when(myClass).getExcelFileParser();
Can you pass AnotherObject as a parameter into the method m rather than calling getAnotherObject() in the method itself?
Preface: I use EasyMock not Mockito so this may be a bit off.
Can't you create an inner subclass of MyClass in your test that overrides getExcelFileParser and has it return a mock? Like this:
public class MyClassMock extends MyClass {
ExcelFileParser _mock;
public MyClassMock(ExcelFileParser mock) {
_mock = mock;
}
#Override
public ExcelFileParser getExcelFileParser() {
return _mock;
}
}
I haven't tested this so there could be issues with this, but the basic idea should be right.

Categories

Resources