Mockito: Mock private field initialization - java

How I can mock a field variable which is being initialized inline?
class Test {
private Person person = new Person();
...
public void testMethod() {
person.someMethod();
...
}
}
Here I want to mock person.someMethod() while testing the Test.testMethod() method for which I need to mock initialization of person variable. Any clue?
Edit: I'm not allowed to modify Person class.

Mockito comes with a helper class to save you some reflection boiler plate code:
import org.mockito.internal.util.reflection.Whitebox;
//...
#Mock
private Person mockedPerson;
private Test underTest;
// ...
#Test
public void testMethod() {
Whitebox.setInternalState(underTest, "person", mockedPerson);
// ...
}
Update:
Unfortunately the mockito team decided to remove the class in Mockito 2. So you are back to writing your own reflection boilerplate code, use another library (e.g. Apache Commons Lang), or simply pilfer the Whitebox class (it is MIT licensed).
Update 2:
JUnit 5 comes with its own ReflectionSupport and AnnotationSupport classes that might be useful and save you from pulling in yet another library.

In case you use Spring Test try org.springframework.test.util.ReflectionTestUtils
ReflectionTestUtils.setField(testObject, "person", mockedPerson);

Pretty late to the party, but I was struck here and got help from a friend. The thing was not to use PowerMock. This works with the latest version of Mockito.
Mockito comes with this org.mockito.internal.util.reflection.FieldSetter.
What it basically does is helps you modify private fields using reflection.
This is how you use it:
#Mock
private Person mockedPerson;
private Test underTest;
// ...
#Test
public void testMethod() {
FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);
// ...
verify(mockedPerson).someMethod();
}
This way you can pass a mock object and then verify it later.
Here is the reference.

I already found the solution to this problem which I forgot to post here.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ Test.class })
public class SampleTest {
#Mock
Person person;
#Test
public void testPrintName() throws Exception {
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
Test test= new Test();
test.testMethod();
}
}
Key points to this solution are:
Running my test cases with PowerMockRunner: #RunWith(PowerMockRunner.class)
Instruct Powermock to prepare Test.class for manipulation of private fields: #PrepareForTest({ Test.class })
And finally mock the constructor for Person class:
PowerMockito.mockStatic(Person.class);
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);

Following code can be used to initialize mapper in REST client mock. The mapper field is private and needs to be set during unit test setup.
import org.mockito.internal.util.reflection.FieldSetter;
new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());

if u are using spring boot test and cant find neither of WhiteBox, FeildSetter; u can simply use org.springframework.test.util.ReflectionTestUtils
this is an example:
import org.springframework.test.util.ReflectionTestUtils;
//...
#Mock
private Person mockedPerson;
private Test underTest;
// ...
#Test
public void testMethod() {
ReflectionTestUtils.setField(underTestObject, "person", mockedPerson);
// ...
}

Using #Jarda's guide you can define this if you need to set the variable the same value for all tests:
#Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}
But beware that setting private values to be different should be handled with care. If they are private are for some reason.
Example, I use it, for example, to change the wait time of a sleep in the unit tests. In real examples I want to sleep for 10 seconds but in unit-test I'm satisfied if it's immediate. In integration tests you should test the real value.

The best way until now, I think that is
org.springframework.test.util.ReflectionTestUtils
Im about to mock the private String mockField in FooService.class inside FooServiceTest.java
FooService.java:
#Value("${url.image.latest}")
private String latestImageUrl;
FooServiceTest.java:
#InjectMocks
FooService service;
#BeforeEach
void setUp() {
ReflectionTestUtils.setField(service, // inject into this object
"latestImageUrl", // assign to this field
"your value here"); // object to be injected
}

commons-lang3
import org.apache.commons.lang3.reflect.FieldUtils;
FieldUtils.writeField(object, fieldName, value, true);

Related

How to mock a newly created object for AWSLambda/AWSStepFunctions that uses ClientBuilders?

I have a class that I'm trying to test where it creates a new object of type AWSStepFunctions, and I'm trying to mock it to return a mock of the same type. I cannot change this original line of code, I can only add tests, so I was wondering how I could go about mocking it.
The class looks looks this --
Class class{
public Object handleRequest(Object object, Context context) {
AWSStepFunctions client = AWSStepFunctionsClientBuilder.standard().withClientConfiguration(new ClientConfiguration()).build();
client.startExecution(...);
}
}
The testing code looks like this -
public class ClassTest {
#Test
public void testHandlerRequest() {
mockStatic(AWSStepFunctionsClientBuilder.class); //mockStatic() and when() from PowerMockito
AWSStepFunctions awsStepFunctionsMock = mock(AWSStepFunctions.class);
AWSStepFunctionsClientBuilder awsStepFunctionsClientBuilder = mock(AWSStepFunctionsClientBuilder.class);
ClientConfiguration configuration = mock(ClientConfiguration.class);
PowerMockito.whenNew(ClientConfiguration.class).withAnyArguments().thenReturn(awsStepFunctionsMock);
when(awsStepFunctionsClientBuilder.standard()).thenReturn(awsStepFunctionsClientBuilder);
when(awsStepFunctionsClientBuilder.withClientConfiguration()).thenReturn(awsStepFunctionsClientBuilder);
when(awsStepFunctionsClientBuilder.build()).thenReturn(awsStepFunctionsMock);
... more when-thenreturns
}
}
I'm running into errors such as NoSuchMethodError for the clientBuilder's mock.
I tried to use PowerMockito's whenNew to mock the creation of the new object of type AWSStepFunctions - PowerMockito.whenNew(AWSStepFunctions.class).withAnyArguments().thenReturn(awsStepFunctionsMock), but that doesn't seem to work as well. Is there a way to return this mock correctly?
You can directly mock static methods with Mockito and Junit5 without using Powermock.
ClassTest
#Test
void test() throws IOException {
try (MockedStatic<AWSStepFunctionsClientBuilder> awsMock = Mockito.mockStatic(AWSStepFunctionsClientBuilder.class, Mockito.RETURNS_DEEP_STUBS)) {
AWSStepFunctions awsStepFunctionsMock = mock(AWSStepFunctions.class);
// You can mock methods chaining when you specify Mockito.RETURNS_DEEP_STUBS
awsMock.when(() -> AWSStepFunctionsClientBuilder.standard().withClientConfiguration(Mockito.any()).build()).thenReturn(awsStepFunctionsMock);
}
}
You can read this post for more explanation about MockedStatic: https://www.baeldung.com/mockito-mock-static-methods
And this one about Mockito.RETURNS_DEEP_STUBS: https://www.baeldung.com/mockito-fluent-apis
Don't forget to configure Mockito to handle static mock :
test/resources/mockito-extensions/org.mockito.plugins.MockMaker
mock-maker-inline

Unit testing constructor initialization and public logic

Suppose you have the following class:
public class RepositoryImpl implements Repository {
private static final Object DEFAULT_OBJECT = new Object();
private final Persistence persistence;
private volatile Object cachedObject; // maybe ignore that this is volatile and non-final
public RepositoryImpl(Persistence persistence) {
this.persistence = persistence;
this.cachedObject = getInitialCachedObject();
}
private Object getInitialCachedObject() {
try {
return persistence.get();
} catch (ObjectNotFoundException e) {
persistence.persist(DEFAULT_OBJECT);
return DEFAULT_OBJECT;
}
}
public Object update() { /*some logic*/ }
public Object get() { /*some logic*/ }
public Object delete() { /*some logic*/ }
}
Then I want to unit test the Repository class and I mock out the persistence.
I want to have probably 2 tests that test the initialization logic (happy path and exception) and 3 more tests for the public methods.
The question is how should I approach the testing of this?
The possible options that I managed to think of are:
Consider calling the initialization from outside through a public method after ctor
breaks the immutability (in my particular case this is already broken as cachedObject needs to be volatile and not final, but in the general case.. yeah)
Create the RepositoryImpl in each test case instead of using #InjectMocks or #Before
Create two nested test classes - one for the init logic and one for the core logic
Somehow use #InjectMocks but re-initialize only in one test, not sure if possible
Some lazy approach in get(), but also breaks immutability in the general case
To me option 3 seems clean, but maybe there is a better approach or further refactoring is needed idk. Any suggestions are highly appreciated.
Note that I cannot just use #Cachable in the Persistence because this is not a Spring project.
Create the RepositoryImpl in each test case instead of using #InjectMocks or #Before
Create two nested test classes - one for the init logic and one for the core logic
I think that the options above are viable solutions, but you made a good point here:
Somehow use #InjectMocks but re-initialize only in one test, not sure if possible
To achieve that you can simply ignore the instance stored in the test class field annotated with #InjectMocks and create a separate one, just in this test (as described in your second proposed approach).
#ExtendWith(MockitoExtension.class)
class RepositoryTest {
#Mock
Persistence persistence;
#InjectMocks
RepositoryImpl repository;
#Test
void oneOfMultipleTests() {
// here you're defining the persistence field mock behavior
// and using the repository field
}
#Test
void objectNotFound() {
var emptyPersistence = mock(Persistence.class);
when(emptyPersistence.get()).thenThrow(...);
var emptyBasedRepository = new RepositoryImpl(emptyPersistence);
assertNotNull(emptyBasedRepository);
verify(emptyPersistence).persist(argThat(...));
// assert something else if you want
}
}

Java Unittest Mocked Unittest Not working

I'm trying to create a unittest for the method below (myHostClient), but I'm having some problems with it:
MyClass.java
import com.abc.def.ServiceBuilder
public class MyClass {
#Value("${materialLocation}")
private String materialValue
private static final SERVICEBUILDER = new ServiceBuilder()
#Bean public MyHostServiceClient myHostClient(
#Value(${qualifier_one}) final String qualiferOne,
#Value(${use_service}) final boolean useService) {
if(useService) {
return SERVICEBUILDER
.remote(MyHostServiceClient.class)
.withConfig(qualifierOne)
.withCall(new CallerAttach(Caller.retro(defaultStrategy())), // Error Line2 Here
new SigningVisitor(new CredentialsProvider(materialValue))),
call -> call.doSomeStuff(StuffObject.getStuffInstance()))
.makeClient();
}
#Bean DefaultStrategy<Object> defaultStrategy() {
final int valueA = 1;
final int valueB = 2;
return new DoSomeThingsBuilder()
.retry(valueA)
.doSomethingElse(valueB)
.create();
}
}
And here is my latest unsuccessful attempt at writing a unittest for it:
MyClassTest.java
import org.mockito.Mock
import static org.mockito.Mockito.times
public class MyClassTest {
#Mock
private SERVICEBUILDER serviceBuilder;
private MyClass myClass;
private String qualifierOne = "pass"
#BeforeEach
void setUp() {
myClass = new MyClass();
}
#Test
public void test_myHostClient() {
boolean useService = true;
final MyHostServiceClient result = myclass.myHostClient(qualifierOne, useService); // Error Line1 here
verify(serviceBuilder, times(1));
}
}
I have been trying to mock SERVICEBUILDER and verify that the mocked object is called one time but no luck so far. Right now I'm getting this error:
IllegalArgumentException: Material Name cannot be null
And it points to these lines in my code.
In the Test:
final MyHostServiceClient result = myclass.myHostClient(qualifierOne, useService);
Which points to this line in the module:
.withCall(new CallerAttach(Caller.retro(defaultStrategy())),
Anyone know how I can fix my unittest or write a working one from scratch?
I would say the design of MyClass is quite wrong because it looks like a Spring configuration but apparently it's not. If it is really supposed to be a configuration then I wouldn't even test it like this because it would rather be an integration test. Of course, even in integration tests you can mock dependencies. But the test itself would run differently and you would have to spin up a suitable Spring context, etc.
So given the above, I would rather make MyClass some sort of MyHostServiceClientFactory with removing all of the Spring annotations and then fix the following problems in your code.
SERVICEBUILDER is hardcoded.
SERVICEBUILDER is static final and its value is hardcoded into MyClass. You will not be able to reassign that field with the mocked version. It can still be final but not static then and it's better to use dependency injection here by passing the value through the MyClass constructor.
SERVICEBUILDER will still be not mocked even if you fix the above.
To really mock SERVICEBUILDER by using the #Mock annotation in the test you should enable Mockito annotations.
If you are using JUnit5 then you should annotate your test class like this:
#ExtendWith(MockitoExtension.class)
public class MyClassTest {
...
}
If you are stuck with JUnit4 then you should use another combination:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
...
}
Once you've done that the SERVICEBUILDER will be mocked but now you will have to configure the behaviour of that mock, like what is going to be returned by the SERVICEBUILDER methods. I can see 4 methods in total, namely remote, withConfig, withCall, and makeClient. You will have to do Mockito's when/thenReturn configurations.
MyClass.materialValue is null.
But even when your mock will be properly configured you will still encounter the original IllegalArgumentException: Material Name cannot be null. This is because MyClass.materialValue will still be null and looks like CredentialsProvider cannot accept that. As I can see, that field is supposed to be injected by Spring using the #Value annotation, but remember this class no longer contains anything from Spring. As in problem 1, you have to pass the value through the MyClass constructor.
Once all of these problems are solved you can introduce a thin Spring configuration like MyHostServiceClientConfiguration (or whatever name suits you) that would serve as a provider of necessary properties/dependencies for MyHostServiceClientFactory (existing MyClass) and then this factory can provide you with a MyHostServiceClient bean through a method like MyHostServiceClientConfiguration#myHostServiceClient annotated with #Bean.
Conceptually your MyHostServiceClientFactory will look like this:
public class MyHostServiceClientFactory {
private final String materialValue;
private final ServiceBuilder serviceBuilder;
public MyHostServiceClientFactory(String materialValue, ServiceBuilder serviceBuilder) {
this.materialValue = materialValue;
this.serviceBuilder = serviceBuilder;
}
public MyHostServiceClient myHostClient(String qualiferOne, boolean useService) {
if(useService) {
return serviceBuilder
.remote(MyHostServiceClient.class)
.withConfig(qualifierOne)
.withCall(new CallerAttach(Caller.retro(defaultStrategy())), // Error Line2 Here
new SigningVisitor(new CredentialsProvider(materialValue))),
call -> call.doSomeStuff(StuffObject.getStuffInstance()))
.makeClient();
}
// can also be injected as a dependency rather than being hardcoded
DefaultStrategy<Object> defaultStrategy() {
final int valueA = 1;
final int valueB = 2;
return new DoSomeThingsBuilder()
.retry(valueA)
.doSomethingElse(valueB)
.create();
}
}

Easymock andReturn(a mock) returns null

Using EasyMock 3.2, I have a test that is essentially the same as the one I have below. When I run this test there is a null pointer exception when the SUT tries to do daoSupport.getHibernateTemplate().loadAll(); When the mocked daoSupport is supposed to return the mocked template, it returns null.
#RunWith(EasyMockRunner.class)
public class DAOImplTest extends EasyMockSupport {
#Mock
private HibernateDaoSupport daoSupport;
#Mock
private HibernateTemplate template;
#Test
public void test() {
expect(daoSupport.getHibernateTemplate()).andReturn(template).once(); //1
expect(template.loadAll()).andReturn(Collections.emptyList()).once(); //2
replayAll();
SUT mySUT = new SUT(daoSupport);
mySUT.exercise();
verifyAll();
}
}
I can get the test to work by replacing //1 in the snippet above here with
daoSupport.setHibernateTemplate(template);
Obviously this is not what I want to do. I want the mocked daoSupport to return the mocked template. What is wrong here?
The reason, as discribed in the EasyMock documentation:
Final methods cannot be mocked. If called, their normal code will be executed.
It just so happens that HibernateDaoSupport#getHibernateTemplate() is final. Since I can not change the method signature, the best I can do is to extract an interface for this class. Alternatively I can use Powermock, as mentioned in this answer.
At the end of the day, executing the normal code of the getter is not so bad. It's just a getter.

Mockito: How to replace method of class which is invoked by class under test?

Unfortunately the Mockito documentation lacks of exhaustive information, it's difficult to find the proper way how to create the following setup.
I have a class "ResourceManager" which should be tested. This class instantiates another class "JerseyClient" which has a method called "get". I want "ResourceManager" to not invoke the real "JerseyClient" but a mock (or a stub?) from it (It's already unclear to me what is the difference between mocking and stubbing or mocks and spies in Mockito context).
My attempts are to #Mock (or #Spy?) JerseyClient, or at least one method of it:
#RunWith(MockitoJUnitRunner.class)
public class ResourceManagerTest
{
#Mock
private JerseyClient jerseyClient;
#Test
public void testResultHandling() throws JsonGenerationException, JsonMappingException, IOException, ResourceException
{
TestEntity testEntity = new TestEntity();
ResourceManager resourceManager = new ResourceManager();
testEntity.setGet(true);
testEntity.setTestAttribute("1stTest");
when(jerseyClient.get(anyString())).thenReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}");
// doReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}").when(jerseyClient).get(anyString());
TestEntity result = (TestEntity)resourceManager.execute(testEntity, TestEntity.class);
assertThat(result, is(notNullValue()));
assertThat(result.getMessage(), is("success"));
assertThat(result.getTestAttribute(), is("2ndTest"));
}
}
As you can see, I tried to mock jerseyClient.get() method to return a predefined JSON string:
when(jerseyClient.get(anyString())).thenReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}");
or
doReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}").when(jerseyClient).get(anyString());
But none of them work. That means that the real JerseyClient.get method is invoked, because it tries to make a HTTP request with the real JerseyClient.
What is the solution and what is this what I want to do here? Is it spying on a real object or mocking an object where I want to mock a method of it, and when can I replace methods, only on mocks or only on spies?
I found the answer on my own. I need to add
#InjectMocks
private ResourceManager resourceManager;
Then I need to run the test with this instance:
#RunWith(MockitoJUnitRunner.class)
public class ResourceManagerTest
{
#Mock
private JerseyClient jerseyClient;
#InjectMocks
private ResourceManager resourceManager;
#Test
public void testResultHandling() throws JsonGenerationException, JsonMappingException, IOException, ResourceException
{
TestEntity testEntity = new TestEntity();
testEntity.setGet(true);
testEntity.setTestAttribute("1stTest");
when(jerseyClient.get(anyString())).thenReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}");
TestEntity result = (TestEntity)resourceManager.execute(testEntity, TestEntity.class);
assertThat(result, is(notNullValue()));
assertThat(result.getMessage(), is("success"));
assertThat(result.getTestAttribute(), is("2ndTest"));
}
}
And I can also use the "doReturn...when" pattern.

Categories