Mock a constructor with parameter - java

I have a class as below:
public class A {
public A(String test) {
bla bla bla
}
public String check() {
bla bla bla
}
}
The logic in the constructor A(String test) and check() are the things I am trying to mock. I want any calls like: new A($$$any string$$$).check() returns a dummy string "test".
I tried:
A a = mock(A.class);
when(a.check()).thenReturn("test");
String test = a.check(); // to this point, everything works. test shows as "tests"
whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk);
// also tried:
//whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk);
new A("random string").check(); // this doesn't work
But it doesn't seem to be working. new A($$$any string$$$).check() is still going through the constructor logic instead of fetch the mocked object of A.

The code you posted works for me with the latest version of Mockito and Powermockito. Maybe you haven't prepared A?
Try this:
A.java
public class A {
private final String test;
public A(String test) {
this.test = test;
}
public String check() {
return "checked " + this.test;
}
}
MockA.java
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class MockA {
#Test
public void test_not_mocked() throws Throwable {
assertThat(new A("random string").check(), equalTo("checked random string"));
}
#Test
public void test_mocked() throws Throwable {
A a = mock(A.class);
when(a.check()).thenReturn("test");
PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
assertThat(new A("random string").check(), equalTo("test"));
}
}
Both tests should pass with mockito 1.9.0, powermockito 1.4.12 and junit 4.8.2

To my knowledge, you can't mock constructors with mockito, only methods. But according to the wiki on the Mockito google code page there is a way to mock the constructor behavior by creating a method in your class which return a new instance of that class. then you can mock out that method. Below is an excerpt directly from the Mockito wiki:
Pattern 1 - using one-line methods for object creation
To use pattern 1 (testing a class called MyClass), you would replace a call like
Foo foo = new Foo( a, b, c );
with
Foo foo = makeFoo( a, b, c );
and write a one-line method
Foo makeFoo( A a, B b, C c ) {
return new Foo( a, b, c );
}
It's important that you don't include any logic in the method; just the one line that creates the
object. The reason for this is that the method itself is never going
to be unit tested.
When you come to test the class, the object that you test will
actually be a Mockito spy, with this method overridden, to return a
mock. What you're testing is therefore not the class itself, but a
very slightly modified version of it.
Your test class might contain members like
#Mock private Foo mockFoo;
private MyClass toTest = spy(new MyClass());
Lastly, inside your test method you mock out the call to
makeFoo with a line like
doReturn( mockFoo )
.when( toTest )
.makeFoo( any( A.class ), any( B.class ), any( C.class ));
You can use matchers that are more specific than any() if you want to
check the arguments that are passed to the constructor.
If you're just wanting to return a mocked object of your class I think this should work for you. In any case you can read more about mocking object creation here:
http://code.google.com/p/mockito/wiki/MockingObjectCreation

With Mockito you can use withSettings(). For example if the CounterService required 2 dependencies, you can pass them as a mock:
UserService userService = Mockito.mock(UserService.class);
SearchService searchService = Mockito.mock(SearchService.class);
CounterService counterService = Mockito.mock(CounterService.class, withSettings().useConstructor(userService, searchService));

Starting with version 3.5.0 of Mockito and using the InlineMockMaker, you can now mock object constructions:
try (MockedConstruction mocked = mockConstruction(A.class)) {
A a = new A();
when(a.check()).thenReturn("bar");
}
Inside the try-with-resources construct all object constructions are returning a mock.

Without Using Powermock .... See the example below based on Ben Glasser answer since it took me some time to figure it out ..hope that saves some times ...
Original Class :
public class AClazz {
public void updateObject(CClazz cClazzObj) {
log.debug("Bundler set.");
cClazzObj.setBundler(new BClazz(cClazzObj, 10));
}
}
Modified Class :
#Slf4j
public class AClazz {
public void updateObject(CClazz cClazzObj) {
log.debug("Bundler set.");
cClazzObj.setBundler(getBObject(cClazzObj, 10));
}
protected BClazz getBObject(CClazz cClazzObj, int i) {
return new BClazz(cClazzObj, 10);
}
}
Test Class
public class AClazzTest {
#InjectMocks
#Spy
private AClazz aClazzObj;
#Mock
private CClazz cClazzObj;
#Mock
private BClazz bClassObj;
#Before
public void setUp() throws Exception {
Mockito.doReturn(bClassObj)
.when(aClazzObj)
.getBObject(Mockito.eq(cClazzObj), Mockito.anyInt());
}
#Test
public void testConfigStrategy() {
aClazzObj.updateObject(cClazzObj);
Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj);
}
}

Mockito has limitations testing final, static, and private methods.
Alternate Solution:
with jMockit testing library, you can do few stuff very easy and straight-forward as below:
Mock constructor of a java.io.File class:
new MockUp<File>(){
#Mock
public void $init(String pathname){
System.out.println(pathname);
// or do whatever you want
}
};
the public constructor name should be replaced with $init
arguments and exceptions thrown remains same
return type should be defined as void
Mock a static method:
remove static from the method mock signature
method signature remains same otherwise

Using Mockito 4 (but I suspect this is true for Mockito from 3.5.0 version) you can mock the constructor and, in the initializer, you can assert the values of the parameters.
For example:
try (MockedConstruction<A> constr = mockConstruction(A.class,
(mock, context) -> {
if (context.getCount() == 1) {
assertArrayEquals(context.arguments().toArray(), new Object[] {"test"});
} else {
fail("No more calls should happen");
}
})) {
// Do the rest of assertions.
}
Notice that you need to put the MockedConstruction instantiation in a try-with-resources otherwise the mocked construction is leaked outside the test.

Related

Junit Jupiter: How can I change a mockito mock behavior cached in a List outside the test class?

In my scenario, I have a simple class with a method returning a String:
public class Foo {
public String bar() {
return "1";
}
}
For simplification, a List will store instances of Foo (in real life project, this is some kind of a factory/cache combination):
public class FooCache {
private static List<Foo> cache = new ArrayList<>();
public static Foo getOrCreateFoo(Foo foo) {
if (cache.isEmpty()) {
cache.add(foo);
}
return cache.get(0);
}
}
My junit 5 test will fail as soon as I try to reassign the return value of Foo#bar in different test scenarios:
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class FooTest {
#Mock
private Foo foo;
#Test
void firstTest() {
// Arrange
when(foo.bar()).thenReturn("2");
// Act
Foo uut = FooCache.getOrCreateFoo(foo);
String actual = uut.bar();
// Assert
assertEquals("2", actual);
}
#Test
void secondTest() {
// Arrange
when(foo.bar()).thenReturn("3"); // <--- HAS NO EFFECT ON CACHED FOO
// Act
Foo uut = FooCache.getOrCreateFoo(foo);
String actual = uut.bar();
// Assert
assertEquals("3", actual); // fails with 3 not equals 2
}
}
First test method firstTest finishes with success, foo returns "2" and foo is now stored in the cache list.
Second test method secondTest fails with "2 does not equal 3", since
when(foo.bar()).thenReturn("3")
will change the behavior of foo, but has no effect on the mocked object in the cache which will be used calling FooCache#getOrCreateFoo.
Why is that the case and is there any way I can change a mocked object behavior after is got stored in a list outside the test class?
Just to explain what's happening here:
before firstTest() is started, a new Foo mock is created, that later returns "2". This is added to the static cache. The assert is correct.
before secondTest() is started, a another new Foo mock is created, that later returns "3". This is added to the static cache. As the code is static, the first mock is still contained, making the assert to fail!
Lessons to learn:
Static code is evil, especially static non-constant class attributes. Even factories should be created/used in a non-static manner. The singleton pattern is an anti-pattern.
Solutions:
Remove all static modifiers from your code.
Instanciate your FooCache on every test run:
public class FooTest {
#Mock
private Foo foo;
// System Under Test (will be instanciated before every test)
// This is the object that you are actually testing.
private FooCache sut = new FooCache();
#Test
void firstTest() {
// Arrange
when(foo.bar()).thenReturn("2");
// Act
Foo uut = sut.getOrCreateFoo(foo);
String actual = uut.bar();
// Assert
assertEquals("2", actual);
}
#Test
void secondTest() {
// Arrange
when(foo.bar()).thenReturn("3");
// Act
Foo uut = sut.getOrCreateFoo(foo);
String actual = uut.bar();
// Assert
assertEquals("3", actual); // fails with 3 not equals 2
}
}
There are multiple ways of solving this issue
Refactor your static class and include a clearCache method
public class FooCache {
private static List<Foo> cache = new ArrayList<>();
public static Foo getOrCreateFoo(Foo foo) {
if (cache.isEmpty()) {
cache.add(foo);
}
return cache.get(0);
}
public static void clearFooCache() {
cache.clear();
}
}
And in your test
#BeforeEach
public void setUp() {
FooCache.clearCache();
}
Use reflection to access FooCache#cache
#BeforeEach
public void setUp() {
Field cache = FooCache.class.getDeclaredField("cache");
cache.setAccessible(true);
List<Foo> listOfFoos = (List<Foo>)cache.get(FooCache.class);
listOfFoos.clear();
}
Use Mockito's mockStatic utility inside of each test
try(MockedStatic<FooCache> theMock = Mockito.mockStatic(YearMonth.class, Mockito.CALLS_REAL_METHODS)) {
doReturn(anyValue).when(theMock).getOrCreateFoo(any());
}
Just found the reason: As in https://stackoverflow.com/a/16816423/944440 and its first and second comments described, "JUnit designers wanted test isolation between test methods, so it creates a new instance of the test class to run each test method."
So the foo from the first method is stored in the list, and with start of second test method, another foo has been created! Any following changes will not affect the first methods foo anymore.
Not only this is a problem in my szenario, but also when working with Singletons

Spy object value not changed with when, thenReturn

public class MainClass {
public void method1() {
…….
String str = getMethod2();
method3(str);
}
protected String getMethod2() {
String str = “Actual Value”
return str;
}
private void method3(String strparam) {
……
}
}
#RunWith(MockitoJunitRunner.class)
public class Testclass {
#InjectMocks
MainClass obj = new MainClass();
……
#Test
public void testSpy() {
MainClass spyMain = spy(obj);
when(spyMain.getMethod2()).thenReturn(new String("Testing spy"));
obj.method1();
……..
}
}
Want to use a new value returned from getMethod2() from test as it’ll be passed to method3.
I was under the impression that the call to method1 from test class calls method2 and I thought the value retuned from method2 is “Testing spy” but is “Actual Value” and the “Actual Value” is passed to method3 when test class is ran.
How to use the new value from test class?
You are calling the method on obj (obj.method1();), instead of on the object that you've spied: spyMain.method1();.
Assuming the code in your example is actually java code and the capitalization was added when you copied it into Microsoft Word (or some other word processor),
try this:
public void testSpy()
{
MainClass spyMain = spy(obj);
doReturn("Blammy").when(spyMain).getMethod2();
obj.method1();
}
Here are some more info:
The test class must be in the same package as the MainClass.
For example:
Location of MainClass: src/main/java/blammy/MainClass.java
Location of TestClass: src/test/java/blammy/TestClass.java
The doReturn variation of mocking does not call the wrapped method,
but the thenReturn variation does.
This is wrong:
#InjectMocks
MainClass obj = new MainClass();
Only use the #InjectMocks annotation if you are calling MockitoAnnotations.initMocks(class).
Here is your test class rewritten to use #InjectMocks
#RunWith(MockitoJunitRunner.class)
public class Testclass
{
#InjectMocks
private MainClass classToTest;
#Before
public void beforeTest()
{
MockitoAnnotations.initMocks(this)
}
#Test
public void testSpy()
{
spyClassToTest = spy(classToTest);
doReturn("Testing spy").when(spyClassToTest ).getMethod2();
spyClassToTest.method1();
}
}
More Notes:
You may be able to use #Spy and #InjectMocks on the same object
(in my example, on classToTest),
but I never do that.

How to mock a static method in side a public class using Power mockito?

Hi every one I am trying to mock a static method name mapCreditInfo(UCIPin, creditAssessmentResults) which has two parameters UCIPin and creditAssessmentResults. UCIPin is String type and creditAssessmentResults is List
This method is inside a public class ResponseMapper
type as shown below:
private CreditInfo getAccountByUCI(String audiUser, String UCIPin) throws EnterpriseCustomerVerificationException {
List<CreditAssessmentResult> creditAssessmentResults = creditInfoRepository.getUCISummary(UCIPin, audiUser);
return ResponseMapper.mapCreditInfo(UCIPin, creditAssessmentResults);
}
Note: getAccountbyUCI method is called inside another public method
name executeCustomerVerification which is in the class
EnterpriseCustomerVerificationService
ResponseMapper class
public class ResponseMapper {
public static CreditInfo mapCreditInfo(String UCIPin, List<CreditAssessmentResult> creditAssessmentResults) {
CreditInfo creditInfo = new CreditInfo();
creditInfo.setUCIPin(UCIPin);
List<AccountCreditInfo> accountCreditInfos = new ArrayList<AccountCreditInfo>();
for (CreditAssessmentResult creditAssessmentResult : creditAssessmentResults) {
AccountCreditInfo accountCreditInfo = new AccountCreditInfo();
accountCreditInfo.setDelinquenctBalance(creditAssessmentResult.getPastDueAmount());
accountCreditInfo.setNonPayDisconnect(creditAssessmentResult.getNonpayDiscount());
accountCreditInfo.setPreviousAccountNumber(creditAssessmentResult.getAccountNumber());
accountCreditInfo.setUnreturnedEquipmentFlag(creditAssessmentResult.getUnreturnedEquipment());
accountCreditInfos.add(accountCreditInfo);
}
creditInfo.setAccountCreditInfo(accountCreditInfos);
return creditInfo;
}
}
I have Tried like some portion of my test class as shown below :
Test Class
#PrepareForTest( EnterpriseCustomerVerificationService.class)
#RunWith(PowerMockRunner.class)
public class EnterpriseCustomerVerificationServiceTest {
#InjectMocks
private EnterpriseCustomerVerificationService enterpriseCustormerVerificationServiceMock ;
#Test
public void executeCustomerVerificationTest() throws Exception {
List<ErrorResponse> errorResponses = getErrorResponse();
List<String> mso = new ArrayList<String>();
mso.add("a");
mso.add("b");
mso.add("c");
AddressResponse addressResponse = getAddressResponse();
String experianAuthorization = "experianAuthorization";
String UCIPin = "110019";
String auditUser = "ABC";
CreditInfo credit = getCreditInfo();
CreditCheck creditCheck = getcreditCheck();
EnterpriseCustomerVerificationService spy = PowerMockito.spy(new EnterpriseCustomerVerificationService());
PowerMockito.when(spy,PowerMockito.method(EnterpriseCustomerVerificationService.class,"executeCreditCheck",CreditCheck.class)).withArguments(Mockito.any()).thenReturn("#1");
Mockito.when(creditInfoRepository.getUCISummary("110019", "test")).thenReturn(getCreditAssessmentResultList());
PowerMockito.mockStatic(ResponseMapper.class);
Mockito.when(ResponseMapper.mapCreditInfo(UCIPin, getCreditAssessmentResultList())).thenReturn(credit);
CustomerVerification cv = spy
.executeCustomerVerification(getCustomerVerificationRequest1(),
"101");
}
My question is how to mock static mapCreditInfo method using power Mockito ?
Thanks
Like this ...
#RunWith(PowerMockRunner.class)
#PrepareForTest({ResponseMapper.class})
public class ATest {
#Test
public void testMockingStatic() {
PowerMockito.mockStatic(ResponseMapper.class);
// if you want to use specific argument matchers
Mockito.when(ResponseMapper.mapCreditInfo(
uciPin, creditAssessmentResults)
).thenReturn(creditInfo);
// or if you want to match on any arguments passed into your static method ...
Mockito.when(ResponseMapper.mapCreditInfo(
ArgumentMatchers.anyString(),
ArgumentMatchers.anyList())
).thenReturn(creditInfo);
// ...
}
}
Notes:
#PrepareForTest prepares the class with the static methods which you want to mock
PowerMockito.mockStatic mocks all static methods that class
You can use standard Mockito when/then constructs to tell the mocked static methods what to return
The example above uses these dependencies:
org.mockito:mockito-core:2.7.19
org.powermock:powermock-module-junit4:1.7.0
org.powermock:powermock-api-mockito2:1.7.0
Update 1: based on your updated question which shows your test method ...
My example includes: #PrepareForTest({ResponseMapper.class}) your test method is not preparing ResponseMapper instead it is preparing EnterpriseCustomerVerificationService. It's like you are preparing the class which calls the class which has a static method rather than preparing the class which contains the static method.
I would strongly suggest creating a new test case - just temporarily - which looks like the one I have provided and use that to show yourself how to mock a static method and once you are comfortable with that then work that into your EnterpriseCustomerVerificationServiceTest.
Is it possible to change the source code? if so maybe you could try to solve the problem without using any mocking framework at all.
see my comment on How To Java Unit Test a Complex Class

How to test void method with private method calls using Mockito

I have the following piece of code
public class A extends B {
private boolean workDone = false;
#Override
public void publicMethod(boolean flag) {
if (!workDone) {
privateMethod();
workDone = true;
}
super.publicMethod(flag);
}
private void privateMethod() {
// some logic here
}
}
I'm new to mocking. I have following doubts. I'm trying to test the public method.
is it possible for me to assert the value of private variable workDone?
is it possible to verify the method call in the super class?
How can I mock the private method call in the method?
If you really want to verify it, you need to change your A class and extract the super call into a private method:
public class A extends B {
private boolean workDone = false;
#Override
public void publicMethod(final boolean flag) {
if (!workDone) {
privateMethod();
workDone = true;
}
callParentPublicMethod(flag);
}
private void callParentPublicMethod(final boolean flag) {
super.publicMethod(flag);
}
private void privateMethod() {
System.out.println("A: privateMethodCalled");
}
}
after this is done you can use PowerMock to verify private method invocations:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ A.class })
public class ATest {
#Test
public void publicMethod_test_false() throws Exception {
A spy = PowerMockito.spy(new A());
spy.publicMethod(false);
PowerMockito.verifyPrivate(spy).invoke("privateMethod");
PowerMockito.verifyPrivate(spy).invoke("callParentPublicMethod", false);
}
#Test
public void publicMethod_test_true() throws Exception {
A spy = PowerMockito.spy(new A());
spy.publicMethod(true);
PowerMockito.verifyPrivate(spy).invoke("privateMethod");
PowerMockito.verifyPrivate(spy).invoke("callParentPublicMethod", true);
}
}
Hope this helps.
When doing unittesting we verify the public observable behavior of the code under test. This is the return values delivered by the CUT and its communication with dependencies.
The private variable and the private methods inside the CUT are implementation details we don't want to test (explicitly) because we want them to be changeable without braking our test.
In rare cases the call to super class methods can be considered as "communication with dependency". In that case you create a spy() of the CUT. But usually this should be considered implementation detail too...
No. Private variables cannot be accessed other than via reflection. Which is usually not preferred, especially in unit tests.
Yes, assuming you get some assertable change do to super class method call. Like the change in the boolean flag
Yes you can using powermockito. For more see here.
Testing Private method using mockito

How to tell a Mockito mock object to return something different the next time it is called?

So, I'm creating a mock object as a static variable on the class level like so... In one test, I want Foo.someMethod() to return a certain value, while in another test, I want it to return a different value. The problem I'm having is that it seems I need to rebuild the mocks to get this to work correctly. I'd like to avoid rebuilding the mocks, and just use the same objects in each test.
class TestClass {
private static Foo mockFoo;
#BeforeClass
public static void setUp() {
mockFoo = mock(Foo.class);
}
#Test
public void test1() {
when(mockFoo.someMethod()).thenReturn(0);
TestObject testObj = new TestObject(mockFoo);
testObj.bar(); // calls mockFoo.someMethod(), receiving 0 as the value
}
#Test
public void test2() {
when(mockFoo.someMethod()).thenReturn(1);
TestObject testObj = new TestObject(mockFoo);
testObj.bar(); // calls mockFoo.someMethod(), STILL receiving 0 as the value, instead of expected 1.
}
}
In the second test, I'm still receiving 0 as the value when testObj.bar() is called... What is the best way to resolve this? Note that I know I could use a different mock of Foo in each test, however, I have to chain multiple requests off of mockFoo, meaning I'd have to do the chaining in each test.
You could also Stub Consecutive Calls (#10 in 2.8.9 api). In this case, you would use multiple thenReturn calls or one thenReturn call with multiple parameters (varargs).
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
public class TestClass {
private Foo mockFoo;
#Before
public void setup() {
setupFoo();
}
#Test
public void testFoo() {
TestObject testObj = new TestObject(mockFoo);
assertEquals(0, testObj.bar());
assertEquals(1, testObj.bar());
assertEquals(-1, testObj.bar());
assertEquals(-1, testObj.bar());
}
private void setupFoo() {
mockFoo = mock(Foo.class);
when(mockFoo.someMethod())
.thenReturn(0)
.thenReturn(1)
.thenReturn(-1); //any subsequent call will return -1
// Or a bit shorter with varargs:
when(mockFoo.someMethod())
.thenReturn(0, 1, -1); //any subsequent call will return -1
}
}
For all who search to return something and then for another call throw exception:
when(mockFoo.someMethod())
.thenReturn(obj1)
.thenReturn(obj2)
.thenThrow(new RuntimeException("Fail"));
or
when(mockFoo.someMethod())
.thenReturn(obj1, obj2)
.thenThrow(new RuntimeException("Fail"));
First of all don't make the mock static. Make it a private field. Just put your setUp class in the #Before not #BeforeClass. It might be run a bunch, but it's cheap.
Secondly, the way you have it right now is the correct way to get a mock to return something different depending on the test.
Or, even cleaner:
when(mockFoo.someMethod()).thenReturn(obj1, obj2);
For Anyone using spy() and the doReturn() instead of the when() method:
what you need to return different object on different calls is this:
doReturn(obj1).doReturn(obj2).when(this.spyFoo).someMethod();
.
For classic mocks:
when(this.mockFoo.someMethod()).thenReturn(obj1, obj2);
or with an exception being thrown:
when(mockFoo.someMethod())
.thenReturn(obj1)
.thenThrow(new IllegalArgumentException())
.thenReturn(obj2, obj3);

Categories

Resources