Easymock andReturn(a mock) returns null - java

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.

Related

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
}
}

Mockito failing inside internal call for mocked method

I'm trying to mock the return value for a method using the when call from mockito. However, I'm new to this and I may perhaps be misunderstanding how mockito works, since the call is failing inside the method mocked when that calls another method. I thought regardless of how that method is implemented, I should be getting the return value I'm asking for? Or do I need to mock also the internals for that method? I feel that shouldn't be it.
public boolean verifyState(HttpServletRequest request, String s) {
String stateToken = getCookieByName(request, STATE_TOKEN);
String authToken = getCookieByName(request, AUTHN);
boolean isValidState = true;
if (isValidState) {
try {
log.info(getEdUserId(stateToken, authToken));
return true;
} catch (Exception e) {
ExceptionLogger.logDetailedError("CookieSessionUtils.verifyState", e);
return false;
}
} else {
return false;
}
}
public String getEdUserId(String stateToken, String authToken) throws Exception {
String edUserId;
Map<String, Object> jwtClaims;
jwtClaims = StateUtils.checkJWT(stateToken, this.stateSharedSecret); // Failing here not generating a proper jwt token
log.info("State Claims: " + jwtClaims);
edUserId = sifAuthorizationService.getEdUserIdFromAuthJWT(authToken);
return edUserId;
}
My test:
#ActiveProfiles(resolver = MyActiveProfileResolver.class)
#WebMvcTest(value = CookieSessionUtils.class, includeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {ApiOriginFilter.class, ValidationFilter.class})})
class CookieSessionUtilsTest {
#Autowired
private CookieSessionUtils cookieSessionUtils; // Service class
#Mock
private CookieSessionUtils cookieSessionUtilsMocked; // Both the method under test and the one mocked are under the same class, so trying these two annotations together.
#Mock
private HttpServletRequest request;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testVerifyState1() throws Exception {
//...Some mocks for getCookieName
UUID uuid = UUID.randomUUID();
when(cookieSessionUtils.getEdUserId(anyString(), anyString()).thenReturn(eq(String.valueOf(uuid))); // When this line runs it fails on verifyState method
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
UPDATE
Attempt using anyString() instead of eq().
Thank you.
Your test is broken in a few places.
Setting expectations on a real object
You should call Mockito.when on mocks and spies, not on System under test. Mockito normally reports it with a clear error message, but you throw a NPE from getEdUserId, so this is reported instead. The NPE stems from the fact that both eq and anyString return null, which is passed to the real method.
Invalid use of matchers
As #StefanD explained in his answer eq("anyString()") is not matching any string. It matches only one string "anyString()"
Returning a mather instead of real object
thenReturn(eq(String.valueOf(uuid)))
This is illegal position for a matcher.
Mixing Mockito and Spring annotations in a WebMvcTest
This is a common error. Mockito does not inject beans to the spring context.
From the code provided it is unclear what CookieSessionUtils is (Controller? ControllerAdvice?) and what is the correct way to test it.
Update
It seems that you are trying to replace some methods under test. A way to do it is to use a Spy.
See https://towardsdatascience.com/mocking-a-method-in-the-same-test-class-using-mockito-b8f997916109
The test written in this style:
#ExtendWith(MockitoExtension.class)
class CookieSessionUtilsTest {
#Mock
private HttpServletRequest request;
#Mock
private SifAuthorizationService sifAuthorizationService;
#Spy
#InjectMocks
private CookieSessionUtils cookieSessionUtils;
#Test
public void testVerifyState1() throws Exception {
Cookie cookie1 = new Cookie("stateToken", "stateToken");
Cookie cookie2 = new Cookie("Authn", "Authn");
when(request.getCookies()).thenReturn(new Cookie[]{cookie1, cookie2});
UUID uuid = UUID.randomUUID();
doReturn(String.valueOf(uuid)).when(cookieSessionUtils).getEdUserId(anyString(), anyString());
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
}
An alternative way is to call the real method, but to mock all collaborators: StateUtils and sifAuthorizationService. I would probably go with this one, if you want to test public getEdUserId.
Test written when mocking collaborators:
#ExtendWith(MockitoExtension.class)
class CookieSessionUtilsTest {
#Mock
private HttpServletRequest request;
#Mock
private SifAuthorizationService sifAuthorizationService;
#InjectMocks
private CookieSessionUtils cookieSessionUtils;
#Test
public void testVerifyState1() throws Exception {
Cookie cookie1 = new Cookie("stateToken", "stateToken");
Cookie cookie2 = new Cookie("Authn", "Authn");
when(request.getCookies()).thenReturn(new Cookie[]{cookie1, cookie2});
UUID uuid = UUID.randomUUID();
when(sifAuthorizationService.getEdUserIdFromAuthJWT(cookie2.getValue())).thenReturn(String.valueOf(uuid));
assertTrue(cookieSessionUtils.verifyState(request, ""));
}
}
I took the assumption that StateUtils.checkJWT does not need to be mocked
The points above are still valid and need to be resolved in either case.
Remarks
As the system under test is currently a Service, I suggest to drop WebMvcTest and test it with plain mockito instead.
Should SUT be a service? It is more typical to handle auth code in filters.
note usage of doReturn when stubbing a method on a spy.
You use mocks in more places than needed. For example Cookie is trivial to construct, there is no point in using a mock
The error is here:
when(cookieSessionUtils.getEdUserId(eq("anyString()"), eq("anyString()"))).thenReturn(eq(String.valueOf(uuid)));
It should read like
when(cookieSessionUtils.getEdUserId(anyString()), anyString()).thenReturn(uuid);
Please refer to the Mockito documentation of Argument matchers.
Because the argument matchers looking for the string "anyString()" they never match the actual parameters the method call is providing and so there is never returned the uuid you expecting.

Testing a method calling a method in the same class which calls a method of service class [duplicate]

This question already has answers here:
Mockito - difference between doReturn() and when()
(5 answers)
Closed 2 years ago.
I'm pretty new to Junit and I'm trying to test isApproved method in Junit. I'm am mocking isDateValidOfData method using when and thenReturn using
Mockito.when(isDateValidOfData(anyLong(), anyString()).thenReturn(true);
This is getting an indexOutOfBounds exception. Here the serviceClass is being called on argument matchers so returning nothing in the list of data. I just want to know is there a way to mock the data and test it using Mockito and Junit.
Using spy to get the object of the same class to call the method.
MyClass {
//Service class calls the repository to fetch data.
#Autowired
ServiceClass serviceClass;
public boolean isApproved(Long id, String code) {
// Validation is done on the arguments
//if id is of a particular type then return true by default
//if code is in a list already present then continue with the below code or else return true by default.
return isDateValidOfData(Long id, String code);
}
public boolean isDateValidOfData(Long id, String code) {
List<Data> data = serviceObject.getData(id, code);
LocalDateTime eDate = data.get(0).getEDate();
LocalDateTime rDate = data.get(0).getRDate();
// check if eDate and rDate is greater than current date, if yes return true or return false
}
}
#RunWith(SpringRunner.class)
TestClass {
#InjectMocks
MyClass myClass;
#Test
public void isApprovedTest() {
MyClass myClass1 = Mockito.spy(myClass);
Mockito.when(myClass1.isDateValidOfData(anyLong(), anyString())).thenReturn(true);
Assert.assertTrue(myClass1.isApproved(1234L, "1234");
}
}
Since you are using #InjectMocks you should use #RunWith(MockitoJUnitRunner.class) on class level an everything will work fine.
If you want to use #RunWith(SpringRunner.class) then use #MockBean and #SpyBean to write test.
EDIT:
You can see more #RunWith(SpringRunner.class) vs #RunWith(MockitoJUnitRunner.class) here
Additional, you can check this Why we use Mockitojunitrunner class in our junit test?
and #RunWith(SpringRunner.class) with Spring Boot
Also, please check this one Mockito - difference between doReturn() and when()

Mockito: Mock private field initialization

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);

Can't access methods of #Injectable inside Expectations() of Jmockit?

I define an #Injectable in my test class as below
#Injectable
IndividualPaymentServiceLocal individualPaymentService;
and then initialize this reference inside #Before method of Junit as
individualPaymentService = new MockUp<IndividualPaymentServiceLocal>() {
#Mock
public void $init() {
}
#Mock
public List<IndividualPayment> search(#Nullable String clinicId, #NotNull TimeWindow timeWindow, #Nullable IndividualPaymentFetchConfig fetchConfig) {
return paymentsList_1;
}
}.getMockInstance();
IndividualPaymentServiceLocal is a local EJB interface and has a
search() method that I mock as shown above to return an ArrayList
paymentsList_1. Now in my one of #Test methods, I wish to return a
different ArrayList so I try to use Jmockit's Expectations like below
new Expectations(){
individualPaymentService.search(anyString,any,any); result=paymentsList_2;
};
but search method is not resolved on individualPaymentService reference so code doesn't compile. Outside Expectations, its resolved. Am I missing something? I am using IntelliJ Idea. Please suggest.

Categories