Method that needs to be tested - located in AnalyticsServiceImpl.java class
public void trackSplashState(MeasurementViewEnum measurementViewEnum) {
HashMap<String, Object> data = createCommonData(measurementViewEnum);
MeasureServiceImpl.StartStatus status = mMeasureService.getLaunchStatus();
switch (status) {
case INSTALL:
data.put(APP_EVENT_INSTALL, INSTALL);
break;
case LAUNCH:
data.put(APP_EVENT_LAUNCH, LAUNCH);
break;
case UPDATE:
data.put(APP_EVENT_UPDATE, UPDATE);
break;
}
trackState(measurementViewEnum, data);
}
Test class
#Config(constants = BuildConfig.class, sdk = TestConfig.SDK)
#RunWith(RobolectricTestRunner.class)
public class AnalyticsServiceImplTest {
#Module(includes = TestAppModule.class, injects = AnalyticsServiceImplTest.class, overrides = true)
static class TestModule {
}
#Inject
AnalyticsServiceImpl analyticsServiceImpl;
#Inject
MeasureServiceImpl measureService;
#Inject
Context mContext;
#Inject
LoginService mLoginService;
#Captor
ArgumentCaptor<HashMap<String, Object>> data;
#Captor
ArgumentCaptor<String[]> varargs;
private ArgumentCaptor<MeasurementViewEnum> enumArgumentCaptor;
#Before
public void setUp() throws Exception {
Services.initialize(new AnalyticsServiceImplTest.TestModule()).inject(this);
enumArgumentCaptor = ArgumentCaptor.forClass(MeasurementViewEnum.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void trackSplashState_shouldReturnInstall_whenLaunchStatusEqualsINSTALL() throws Exception {
analyticsServiceImpl = mock(AnalyticsServiceImpl.class);
MeasureServiceMock measureServiceMock = new MeasureServiceMock();
measureServiceMock.setStatus(MeasureServiceImpl.StartStatus.INSTALL);
analyticsServiceImpl.mMeasureService = measureServiceMock;
analyticsServiceImpl.trackSplashState(MeasurementViewEnum.SPLASH);
verify(analyticsServiceImpl, times(1)).trackState(enumArgumentCaptor.capture(), data.capture());
}
}
when I run this test case I got null pointer exception at the last line. I'm a bit new to unit testing. Can you please explain what is the mistake that I have done in this code?
1) You are mocking the SUT which simply wont work:
analyticsServiceImpl = mock(AnalyticsServiceImpl.class);
You will be verifying its trackState method so you need to Spy on it:
analyticsServiceImpl = spy(new AnalyticsServiceImpl());
2) You are capturing the inputs but you are not asserting them in any way. I guess you missed that:
verify(analyticsServiceImpl, times(1)).trackState(enumArgumentCaptor.capture(), data.capture());
Map<String, Object> dataCaptured = data.getValue();
MeasurementViewEnum enumCapture = enumArgumentCaptor.getValue();
// assert these values
UPDATE:
#Before
public void setUp() throws Exception {
MockitoAnnotation.initMocks(this);
}
Related
I have to test DataIdResolver class and it is a class that has a switch case and optional in it. Also there is a one case and default part of switch case that contains each method call. I need to test it and I am not sure how to do it.
public class DataIdResolver {
final DataService dataService;
public DataIdResolver(DataService dataService) {
this.dataService = dataService;
}
public List<String> fetchDataIds(String dataId){
Optional<DataResponse> optionalResponse = dataService.getData(dataId);
if(optionalResponse.isPresent()) {
switch(optionalResponse.get().author){
case "Harry Potter":
return resolveAuthorDataIdAndSiblingsAuthorDataId(optionalResponse.get());
default:
return resolveServerSideDataIdAndSiblingsServerSideDataId(optionalResponse.get());
}
} else {
return List.of(dataId);
}
}
private List<String> resolveAuthorDataIdAndSiblingsAuthorDataId(DataResponse response) {
List<String> resolvedServerSideIds = new ArrayList<>();
resolvedServerSideIds.add(response.serverSideDataId);
if (!response.siblings.isEmpty()){
for (SiblingsDataResponse s : response.siblings) {
resolvedServerSideIds.add(s.dataId);
}
}
return resolvedServerSideIds;
}
}
Here is what I have for start:
public class DataIdResolverTest {
DataService dataService = Mockito.mock(DataService.class);
RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private final HttpDataService httpDataService = new HttpDataService(restTemplate);
#Test
public void fetchDataIds() {
Optional<DataResponse> optionalResponse = dataService.getData(dataId);
optionalResponse.ifPresent(dataResponse -> Mockito
.when(!dataResponse.siblings.isEmpty()).thenReturn(Boolean.valueOf("siblingsDataId")));
httpDataService.getData("dataIdTest");
}
#Test
public void resolveAuthorDataIdAndSiblingsAuthorDataId(){
}
}
Should I test it all in one test method?
What is the best way to do it?
Any advice appreciated.
Here's example.
public class DataIdResolverTest {
DataService dataService = Mockito.mock(DataService.class);
private final DataIdResolver dataIdResolver = new DataIdResolver(dataService);
#Test
public void fetchDataIds_returnsListWithExceptedString_whenOptionalIsPresent() {
//given
ResponseData responseData = createYourResponseDataHere();
Mockito.when(dataService.getData()).thenReturn(Optional.of(responseData));
//when
List<String> dataIds = dataIdResolver.fetchDataIds();
//then
//here you need to check if your dataIds have expected values, you can use Assertions
//example
Assert.assertEquals("expectedString", dataIds.get(0));
}
#Test
public void fetchDataIds_returnsEmptyList_whenOptionalIsNotPresent() {
//given
ResponseData responseData = createYourResponseDataHere();
Mockito.when(dataService.getData()).thenReturn(Optional.empty());
//when
List<String> dataIds = dataIdResolver.fetchDataIds();
//then
Assert.assertTrue(dataIds.isEmpty());
}
}
In general read more about unit tests. You want test class DataIdResolver but you didn't even create instance of it. You can't test private method without reflection, in general it's bad practice to do it. Also remember to name your test methods better, you can read about it here https://dzone.com/articles/7-popular-unit-test-naming
Junit test case getting failed:
existing static mocking registration must be deregistered
Test class:
#RunWith(MockitoJUnitRunner.class)
public class DeleteReportServiceTest {
#InjectMocks
private ReturnCheckController returnCheckController;
#Mock
MockedStatic<DigitalGatewayRESTClient> mockDigiGateway;
#Before
public void setUp() throws Exception {
this.returnCheckController = new ReturnCheckController();
this.mockDigiGateway = Mockito.mockStatic(DigitalGatewayRESTClient.class);
}
#Test
public void testdeleteReport() throws Exception {
String input = "{\"clientId\": \"1\", \"applicationId\": \"9010\"}";
String response = "{\"success\":true,\"successText\":\"Manual adjustment record deleted\"}";
String expected = "{\"status\":200}";
JSONObject returnJson = new JSONObject(response);
mockDigiGateway.when((Verification) DigitalGatewayRESTClient.getDGRESTConnection(Mockito.any())).thenReturn(returnJson);
String actual = returnCheckController.deleteReport(input);
Assert.assertNotNull(actual);
Assert.assertEquals(expected, actual);
}
#After
public void after() {
mockDigiGateway.close();
}
}
Closing the static mocking still am getting the error.
You can NOT use #Mock and MockedStatic at same time.
Instead, if you want to stub static method of DigitalGatewayRESTClient, you should create a MockedStatic<DigitalGatewayRESTClient> additionally, like this:
private MockedStatic<DigitalGatewayRESTClient> mockedStaticDigiGateway;
Then initialize mockedStaticDigiGateway:
#Before
public void setUp() throws Exception {
this.mockedStaticDigiGateway = Mockito.mockStatic(DigitalGatewayRESTClient.class);
// other setup...
}
and modify your test case, stub mockedStaticDigiGateway.when... instead:
#Test
public void testdeleteReport() throws Exception {
// arrange ...
mockedStaticDigiGateway.when((Verification) DigitalGatewayRESTClient.getDGRESTConnection(Mockito.any()))
.thenReturn(returnJson);
// assert...
}
Finally, close mockedStaticDigiGateway after test is finished:
#After
public void after() {
mockedStaticDigiGateway.close();
}
I think it will work correctly although one year passed.
Below is main code consist of one util class and service class using it
#PropertySource("classpath:atlas-application.properties")
public class ApacheAtlasUtils {
#Value("${atlas.rest.address}")
private String atlasURL;
#Value("${atlas.rest.user}")
private String atlasUsername;
#Value("${atlas.rest.password}")
private String atlasPassword;
private AtlasClientV2 client;
public AtlasClientV2 createClient() {
if (client == null) {
return new AtlasClientV2(new String[] {atlasURL}, new String[] {atlasUsername, atlasPassword});
} else {
return client;
}
}
}
Service Class is below :-
#Override
public Page<SearchResultDto> findFilesWithPages(QueryParent queryParent, Pageable pageable)
throws AtlasServiceException {
// Some code
client = new ApacheAtlasUtils().createClient();
//some code
}
I am writing unit test for service method and I am getting exception for createClient method asking for values for url, username and password which should not happen as this should be mocked but the mocking is giving me below error
java.lang.IllegalArgumentException: Base URL cannot be null or empty.
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:141)
at org.apache.atlas.AtlasServerEnsemble.<init>(AtlasServerEnsemble.java:35)
at org.apache.atlas.AtlasBaseClient.determineActiveServiceURL(AtlasBaseClient.java:318)
at org.apache.atlas.AtlasBaseClient.initializeState(AtlasBaseClient.java:460)
at org.apache.atlas.AtlasBaseClient.initializeState(AtlasBaseClient.java:448)
at org.apache.atlas.AtlasBaseClient.<init>(AtlasBaseClient.java:132)
at org.apache.atlas.AtlasClientV2.<init>(AtlasClientV2.java:82)
at com.jlr.stratus.commons.utils.ApacheAtlasUtils.createClient(ApacheAtlasUtils.java:40)
at com.jlr.stratus.rest.service.impl.FileSearchService.findFilesWithPages(FileSearchService.java:49)
The Test code is as follows:-
private FileSearchService fileSearchService;
#Spy
private ApacheAtlasUtils apacheAtlasUtils;
#Mock
private AtlasClientV2 client;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
fileSearchService = new FileSearchService();
}
#Test
public void findFilesWithPages_searchAll() throws AtlasServiceException {
Mockito.doReturn(client).when(apacheAtlasUtils).createClient();
service.search(queryParent,pageable);
}
Your idea with spying is adequate (you can even go for mocking if you do not actually need any true implementation of that class).
The problem lies in the implementation:
// Some code
client = new ApacheAtlasUtils().createClient();
//some code
}
Instead of having the ApacheAtlasUtils as an instance variable (or a supplier method) you create the instance on the fly.
Mockito is not smart enough to catch that operation and replace the real object with you spy.
With the supplier method you can set up your test as follows:
#Spy
private FileSearchService fileSearchService = new FileSearchService();
#Spy
private ApacheAtlasUtils apacheAtlasUtils = new ApacheAtlasUtils();
#Mock
private AtlasClientV2 client;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
doReturn(apacheAtlasUtils).when(fileSearchService).getApacheUtils();
}
in your SUT:
#Override
public Page<SearchResultDto> findFilesWithPages(QueryParent queryParent, Pageable pageable)
throws AtlasServiceException {
// Some code
client = getApacheUtils().createClient();
//some code
}
ApacheAtlasUtils getApacheUtils(){
return new ApacheAtlasUtils();
}
I have following test:
#RunWith(Parameterized.class)
#SpringBootTest
#ContextConfiguration(classes = MyConfig.class)
public class OrderPlacementCancelTest {
#Autowired
private TestSessionsHolderPerf sessionsHolder;
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
private CommonCredentialSetter commonCredentialSetter;
#Before
public void login() throws InterruptedException {
int attempts = 0;
while (!sessionsHolder.isClientLoggedIn() && attempts < 3) {
Thread.sleep(1000);
++attempts;
}
}
#Parameterized.Parameters()
public static Collection<Object[]> data() {
...
}
and following runner:
#Test
public void test() throws Exception {
Class[] cls = {OrderPlacementCancelTest.class};
Result result = JUnitCore.runClasses(new ParallelComputer(false, true), cls);
logger.info("Failure count={}", result.getFailureCount());
for (Failure failure : result.getFailures()) {
logger.error(failure.getTrace());
}
}
When I start test via runner I see that sometimes method login marked as #Before throws NullPointerException because sessionsHolder is null.
How can I avoid it?
It seems that #Parameterized does not mix well with junit rules. One option would be to replace the Rule by performing the logic in the constructor of the parameterized test class, or calling a setup method at the beginning of your test methods.
In either case you can use TestContextManager to populate your test class with the #AutoWired values like this:
private TestContextManager testContextManager;
#Before
public void login() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
The function to be mocked is of class NegotiateNode:
protected String getAttributeValueFromNodeOfServiceType(String serviceType, String attributeName) {
String attributeValue = null;
for (Node node : this.getListOfNodes()) {
if (node.getServiceType().equals(serviceType)) {
attributeValue = node.getAttribute(attributeName);
break;
}
}
return attributeValue;
}
And this is the test:
#Mock private NegotiateNode mockN;
#Mock private Node mockNode;
private List<Node> mockListOfNodes = Arrays.asList(mockNode, mockNode, mockNode);
#Before
public void setup() throws Exception
{
when(mockN.getListofNodes()).thenReturn(mockListofNodes);
}
#Test
public void getAttributeValueFromNodeOfServiceType_ServiceTypeExists_ReturnAttribute() {
when(mockNode.getServiceType()).thenReturn("PMN", "AMC", "SMC");
when(mockNode.getAttribute(anyString()).thenReturn("mockedValue");
when(NegotiateNode.getAttributeValueFromNodeOfServiceType(anyString(), anyString())).thenCallRealMethod();
assertEquals("mockedValue", mockN.getAttributeValueFromNodeOfServiceType("AMC", "dummyAttribute"));
}
I'm getting NullPointerException on running this test. The cause is that inside the for loop value of node is null. This seems to be because of the way List works in java. Is there any workaround for this?
You need to add mockNodes to the list inside the setup method.
#Before
public void setup() throws Exception
{
mockListOfNodes = Arrays.asList(mockNode, mockNode, mockNode);
when(mockN.getListofNodes()).thenReturn(mockListofNodes);
}