I have 2 tests which call the same code but check different things.
The first one uses doAnswer() to stub a method call and put parameters checker.
The second one doesn't need it.
But when I run my tests, the second test fails because fails the checker that was injected in the first test. And if I run only the second test it passes.
So, should I reset doAnswer() stub with empty checker im my setUp() method? Why so?
This is a checker that I use in the first test:
final Map<String, String> expectedParams = new HashMap<>();
expectedParams.put("param1", "A");
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
String name = (String) args[0];
Assert.assertEquals("event1", name);
Map<String, String> params = (Map<String, String>) args[1];
Assert.assertEquals(expectedParams, params);
return null;
}}).when(mMyMockedObject).myTestedMethod(anyString(), anyMap());
and this is the beginning
#Mock
MyMockedClass mMyMockedObject;
#Before
public void setUp() throws Exception {
System.out.println("setUp()");
MockitoAnnotations.initMocks(this);
}
In the second test I never call doAnswer() but my checker is called I don't know why :(
Adding the whole test.
#RunWith(LocalRobolectricTestRunner.class)
#Config(manifest = Config.NONE)
public class MyTest {
private static final String MAIN = "main";
#Mock
MyMockedClass mMyMockedObject;
#Before
public void setUp() throws Exception {
System.out.println("setUp()");
MockitoAnnotations.initMocks(this);
// this will connect MAIN with mMyMockedObject
SomClassICantShareNda.someMethodNda(MAIN, mMyMockedObject);
}
Hey, this is where I understand that this is my fault, not Mockito.
This is where I add new mMyMockedObject but forget to erase old instance of mMyMockedObject (inside SomClassICantShareNda, in static collection). So, after each test new mMyMockedObject will be created and added to collection.
Sorry, that was my fault.
The code duplicated many mocked object, cached them in a static collection and didn't reset it in setUp()
Related
I've to write test for a class that calls an API and then processes the response. The class has two public functions and a private function. The first public method fetches a list of IDs. The second public method is called in a loop for every ID to get details associated with an ID. The private method is called inside the second public method, since the calls to fetch details based on id are made asynchronously.
I'm new to JUnits and while I understand that I should not test the API calls, just my functions, I still don't understand what should the unit tests assert.
Below are my functions:
public List<Integer> fetchVehicleIds(String datasetId) throws ApiException {
VehiclesApi vehiclesApi = new VehiclesApi();
List<Integer> vehicleIds;
vehicleIds = vehiclesApi.vehiclesGetIds(datasetId).getVehicleIds();
return vehicleIds;
}
public List<VehicleResponse> fetchVehicleDetails(String datasetId, List<Integer> vehicleIds) throws InterruptedException, ApiException {
CountDownLatch latch = new CountDownLatch(vehicleIds.size());
List<VehicleResponse> vehiclesList = new ArrayList<>();
for (Integer vehicleId: vehicleIds) {
populateEachVehicleDetail(datasetId, vehicleId, vehiclesList, latch);
}
latch.await();
return vehiclesList;
}
private void populateEachVehicleDetail(String datasetId, Integer vehicleId, List<VehicleResponse> vehiclesList, CountDownLatch latch) throws ApiException {
ApiCallback<VehicleResponse> vehicleResponseApiCallback = new ApiCallback<VehicleResponse>() {
#Override
synchronized public void onSuccess(VehicleResponse result, int statusCode, Map<String, List<String>> responseHeaders) {
vehiclesList.add(result);
latch.countDown();
}
};
VehiclesApi vehiclesApi = new VehiclesApi();
vehiclesApi.vehiclesGetVehicleAsync(datasetId,vehicleId,vehicleResponseApiCallback);
}
Based on the research I've done so far, I think I have to mock the API calls using mockito? I'm still unclear on how the functionality can be unit tested.
These two statements are indeed the things that you want to isolate in your unit test:
private void populateEachVehicleDetail(String datasetId, Integer vehicleId, List<VehicleResponse> vehiclesList, CountDownLatch latch) throws ApiException {
....
VehiclesApi vehiclesApi = new VehiclesApi();
vehiclesApi.vehiclesGetVehicleAsync(datasetId,vehicleId,vehicleResponseApiCallback);
...
}
1) Make you dependency mockable
But you can mock only something that you can set from the client side of the class.
Here the API is a local variable. So you should change your class to expose the dependency, for example in the constructor.
In this way you could mock it easily.
2) Make your mock not return a result but invoke the callback.
In a synchronous invocation context, you want to mock a returned result.
In an asynchronous invocation context with a callback, things are different. Indeed callbacks don't return to the caller but callbacks are invoked to provide the result of the invocation.So here what you want is that the mocked API invokes the onSuccess() callback with mocked parameters that represent the data set for your unit test :
#Override
synchronized public void onSuccess(VehicleResponse result, int statusCode, Map<String, List<String>> responseHeaders) {
vehiclesList.add(result);
latch.countDown();
}
In your unit test you should mock in this way the callback for each expected invocation :
#Mock
VehiclesApi vehiclesApiMock;
// ...
// when the api method is invoked with the expected dataSetId and vehicleId
Mockito.when(vehiclesApiMock.vehiclesGetVehicleAsync(Mockito.eq(datasetId), Mockito.eq(vehicleId),
Mockito.any(ApiCallback.class)))
// I want to invoke the callback with the mocked data
.then(invocationOnMock -> {
ApiCallback<VehicleResponse> callback = invocationOnMock.getArgument(2);
callback.onSuccess(mockedVehicleResponse, mockedStatusCode,
mockedResponseHeaders);
return null; // it is a void method. So no value to return in T then(...).
});
I think that a cast is missing for ApiCallback but you should have the overall idea.
You are right: since you want to test your unit (i.e. the presented code), you should mock the API (mainly: the vehicleApi instance).
As-is right now, there is no way to inject a mocked instance of VehicleApi in your code (well, there is, but it would involve use of reflection... let's not go down this road). You can apply Inversion of Control to make your code testable: instead of constructing a VehicleApi within your object, write a constructor that expects a VehicleApi-instance:
public class YourClass {
private final VehicleApi vehicleApi;
public YourClass(final VehicleApi vehicleApi) {
this.vehicleApi = vehicleApi;
}
[...]
}
What have you won? Well, now you can inject a mocked object into your unit under test:
#RunWith(MockitoJRunner.class)
public class YourClassTest {
private final VehicleApi vehicleApiMock = mock(VehicleApi.class);
private final YourClass underTest = new YourClass(vehicleApiMock);
#Test
void someTest() {
// GIVEN
[wire up your mock if necessary]
// WHEN
[write the test-call]
// THEN
[verify that the unit under test is in the expected state]
}
}
This example assumes JUnit5 as testing- and Mockito as mocking-framework, but there are other options as well.
The test is written in Gherkin language:
- the GIVEN block describes the preconditions, i.e. in which the unit under test and the external (mocked) system(s) are in
- the WHEN block executes the action that should be tested
- the THEN block validates that the unit under test is in the expected state.
#Test(description = "Generate access token")
public void AuthenticationApiTC_30() throws IOException, SQLException {
Map<String, String> positiveDataMap = operations.readRecordFromXls(XLSPATH, FILENAME, POSITIVESHEET);
AuthenticateBuilder builder = new AuthenticateBuilder();
Response response = REQUEST
.headers(builder.authHeaderBuilderForGetReq(positiveDataMap.get("mobilenumber"),
positiveDataMap.get("ssoToken"), positiveDataMap.get("osVersion"),
positiveDataMap.get("deviceID"), positiveDataMap.get("imsi"),
positiveDataMap.get("deviceIDType"), positiveDataMap.get("applicationID"),
positiveDataMap.get("version"), positiveDataMap.get("os")))
.basePath(BASEPATH)
.get();
log.info("AuthenticationApiTC_30\n" + response.prettyPrint());
PostValidators.checkMessageInResponse(response, SuccessMessage.Success);
accessToken = Utils.extractDataFromResponse(response, "result.accessToken");
log.info("Token string :: " + accessToken);
}
My requirement is to get accessToken generated in above #Test method and pass it to another #Test method present in different class.
P.S : I have to do this process again and again as accessToken will be different for different users and test cases.
You can still use normal methods inside your test classes. Instead of having a #Before method, which gets called on every test method, you can create a static helper method which gets called only for some of your test methods. So you can do something like this:
public static Foobar requestToken() {
// ...
}
#Test
public void someTestMethod() {
Foobar x = TestClass.requestToken();
// work with 'x'
}
#Test
public void someOtherTestMethod() {
Foobar x = TestClass.requestToken();
// do other test with 'x'
}
So you don't need to rewrite any code which requests a token but instead use this helper method.
When I used Powermock to mock a private method, and then verify it in another method's unit test, to check if it was called and with correct times. But I found I can verify whether the method was called and with the correct param, the called times of the method can be any number, however the unit test always passed. If someone can help me solve the problem. thx!
This is my source code:
public enum ConversionCommon{
INSTANCE;
...
public void getConvertTypeData(JSONObject result, JSONObject conversionData, String intent){
String uncertainty = "";
String unit1 = "";
String unit1_char = "";
if(result.has(ConversionDefine.CONVERSION_UNCERTAINTY)){
uncertainty = result.getString(ConversionDefine.CONVERSION_UNCERTAINTY);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1)){
unit1 = result.getString(ConversionDefine.CONVERSION_UNIT1);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1_CHAR)){
unit1_char = result.getString(ConversionDefine.CONVERSION_UNIT1_CHAR);
}
setUnitCount(conversionData, uncertainty, intent);
setDestUnits(conversionData, unit1, unit1_char);
}
}
The method getConvertTypeData() calls two methods once. The follow is my test case code:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ConversionCommon.class, LengthConversion.class })
#PowerMockIgnore("javax.management.*")
public class ConversionCommonTest{
#Before
public void setUp() throws Exception{
PowerMockito.mockStatic(LengthConversion.class);//
PowerMockito.spy(LengthConversion.class); //
}
#Test
public void should_getConvertTypeData_invoke_setUnitCount() throws Exception{
JSONObject result = new JSONObject();
JSONObject conversionData = new JSONObject();
result.put(ConversionDefine.CONVERSION_UNCERTAINTY, "3");
result.put(ConversionDefine.CONVERSION_UNIT1, "meter");
result.put(ConversionDefine.CONVERSION_UNIT1_CHAR, "centmeter");
suppress(method(ConversionCommon.class, "setUnitCount", JSONObject.class, String.class, String.class));
ConversionCommon.INSTANCE.getConvertTypeData(result, conversionData, ConversionDefine.INTENT_LENGTH_CONVERSION);
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(1)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
}
The test case can run successful but if I change the last line to ...
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(100)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
... and re-run the test case. The result is also passed. But in fact I only call the method setUnitCount only once in Refo.
The edition of test framework: mockito:1.10.19;powermock:1.6.5
How can I correct verify the private method's call times with the API PowerMockito.verifyPrivate();
You are doing right, except one thing. You're spying on enum constant. And each enums constant is separate inner class. So you have to add two things:
Enum constant to #PrepareForTest with using fullyQualifiedNames, like `#PrepareForTest(values = { ConversionCommon.class, LengthConversion.class }, fullyQualifiedNames = "com.somepackage.ConversionCommon$INSTANCE")
Create a spy for instance: PowerMockito.spy(ConversionCommon.INSTANCE)
Replace constant with spy: Whitebox.setInternalState(ConversionCommon.class, spy)
Now, you can stub the spy method as usual doNothing().when(spy, "setUnitCount");
Code snippet for some abstract singleton implement via enum:
enum
public enum Singleton {
INSTANCE;
public void doSomething(){
callPrivateMethod();
}
private void callPrivateMethod() {
}
}
test
RunWith(PowerMockRunner.class)
#PrepareForTest(value = Singleton.class, fullyQualifiedNames = "com.stackoverflow.q46212600.Singleton$INSTANCE")
public class ClassUseSingletonTest {
#Test
public void should_verify_enum_method() throws Exception {
final Singleton spy = PowerMockito.spy(Singleton.INSTANCE);
Whitebox.setInternalState(Singleton.class, spy);
doNothing().when(spy, "callPrivateMethod");
new ClassUseSingletone().doSomething("do");
PowerMockito.verifyPrivate(Singleton.INSTANCE, times(1)).invoke("callPrivateMethod");
}
}
Full example, you may find here
I am trying to unit test one of my methods using PowerMock and Mockito and getting NUllPointerException for one of the objects which I have already mocked and defined behavior in my test.
This is the code I am trying to test
protected void setTabList() {
List<ActionBar.Tab> list = TabAdapter.get().getAllEnabledTabs();
listAdapter.setTabList(list);
int itemCount = list.size();
if (itemCount == 1 && list.get(0).equals(TabAdapter.KEYPAD_TAB)) {
header.setVisibility(View.VISIBLE);
listAdapter.hide();
}
}
And this is the test code
#RunWith(PowerMockRunner.class)
#PrepareForTest({Log.class, TabFragment.class, TextView.class, SystemProperties.class})
public class TabFragmentTests extends TestCase {
#Before
public void setUp() {
suppress(method(Log.class, "println_native"));
suppress(everythingDeclaredIn(TextView.class));
suppress(method(SystemProperties.class, "native_get_boolean"));
suppress(method(SystemProperties.class, "native_get", String.class));
tabFragment = new TabFragment();
listAdapter = Mockito.mock(TabList.class);
}
#Test
public void testSetTabList() {
assertNotNull(tabFragment);
assertNotNull(listAdapter);
TabAdapter instance = TabAdapter.get();
TabAdapter spy = spy(instance);
List<ActionBar.Tab> list = new ArrayList<ActionBar.Tab>();
list.add(KEYPAD_TAB);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "set Tabs";
}
}).when(listAdapter).setTabList(list);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "hide";
}
}).when(listAdapter).hide();
doReturn(list).when(spy).getAllEnabledTabs();
tabFragment.setTabList();
verify(listAdapter, times(1)).hide();
}
When I run the test and tabFragment.setTabList() is called, listAdapter in setTabList() throws NPE. I am trying to understand why listAdapter.setTabList(list) is not replaced by the "answer" API I have in the test.
I have also tried using Mockito.doNothing().when(listAdapter).setTabList(list) but that doesn't solve the issue.
Another observation is when I create a dummy getTestString(listAdapter) method in my TabFragment class and call it using tabFragment.getTestString(listAdapter) from my test passing mocked listAdapter as an argument, it doesn't through a NPE. Does that mean I have to explicitly pass mocked object to the method call?
You are overriding a method call like this:
when(listAdapter).setTabList(list);
but then you call it like this:
tabFragment.setTabList();
I don't see how that would work. setTabList(list); and setTabList(); call different methods.
I think that you forgot to add "TabAdapter" class to the "PrepareForTest" annotation :
#PrepareForTest({Log.class, TabAdapter.class, TabFragment.class, TextView.class, SystemProperties.class})
Im helper method use ehcache, to reduce queries to Db. Now want to implement JUnit+Mockito test to ensure that ehcache works properly. Have such variant of test:
#Autowired
private DBService service;
#Autowired
private DiscountHelper discountHelper;
#Autowired
private CacheManager cacheManager;
#Before
public void setUp() throws Exception {
assertNotNull(cacheManager);
}
#Test
public void testGetDiscountWithCache() throws RuntimeException,
InterruptedException {
String id1 = "id1";
String id2 = "id2";
String id3 = "id3";
List<String> discountsId = new ArrayList<String>();
discountsId.add(id1);
discountsId.add(id2);
discountsId.add(id3);
List<Map<String, Object>> attrList = new ArrayList<Map<String, Object>>();
attrList.add(new Discount().getAttributes());
attrList.add(new Discount().getAttributes());
attrList.add(new Discount().getAttributes());
Cache cache = cacheManager.getCache(DiscountHelper.CACHE_NAME);
assertNotNull(cache);
assertEquals(0, cache.getSize());
// First run with empty cache
when(service.getAllItems(eq(Discount.TABLE_NAME))).thenReturn(attrList);
List<Discount> actualResult = discountHelper
.getAllDiscountsUsingCache();
assertNotNull(actualResult);
assertEquals(attrList.size(), actualResult.size());
verify(service).getAllItems(eq(Discount.TABLE_NAME));
cache = cacheManager.getCache(DiscountHelper.CACHE_NAME);
// In cache should be 1 record
assertNotNull(cache);
assertEquals(1, cache.getSize());
}
And test method is:
#Cacheable(cacheName = CACHE_NAME, refreshInterval = 1000 * 900, decoratedCacheType = DecoratedCacheType.REFRESHING_SELF_POPULATING_CACHE)
public List<Discount> getAllDiscountsUsingCache() throws RuntimeException,
InterruptedException {
List<Map<String, Object>> result = dbService
.getAllItems(Discount.TABLE_NAME);
List<Discount> discountList = new ArrayList<Discount>();
for (Map<String, Object> entry : result) {
discountList.add(new Discount(entry));
}
return discountList;
}
And this perfectly works. In test i`m sure that after invocation of method I get something in cache. As you can see I also verify that was called method getAllItems in db service. That is good for first time invocation. Next I add second invocation of discountHelper.getAllDiscountsUsingCache() in the same test like this:
when(service.getAllItems(eq(Discount.TABLE_NAME))).thenReturn(attrList);
actualResult = discountHelper
.getAllDiscountsUsingCache();
assertNotNull(actualResult);
assertEquals(attrList.size(), actualResult.size());
verify(service, times(0)).getAllItems(eq(Discount.TABLE_NAME));
So I just want to check that on second invocation there will not be calls to DB service via method getAllItems by this verify: verify(service, times(0)).getAllItems(eq(Discount.TABLE_NAME)); and result will be obtain from cache.
But it doesn't work, I still get invocation of DB method. I find this tutorial http://blog.goyello.com/2010/07/29/quick-start-with-ehcache-annotations-for-spring/ and try variant with delegate object for ehcache testing, but it still invoke db methods on test. What`s wrong?
By the way in production ehcache works good as I see in logs of tomcat, so this is a problem of test. Any suggestions how to fix it?
In the second invocation you use the same mock object (service) created (as I assume from a question's tag) by Springockito during the Spring context initialization. The mock remembers getAllItems() call from the first invocation. You can:
reset the mock before the second invocation using reset(service),
or
check after the second invocation) if there is still one (not two) getAllItems() invocation.