I am trying to create a test for a helper class but I am unable to mock a static call inside the helper class.
This is my class to be tested:
public class NoteHelper {
private NoteService noteService = ServiceBuilder.getService(NoteService.class);
public NoteResponse createNewNote(NoteRequest noteRequest) throws NotAuthorizedException {
Note note = new Note();
note.setContent(noteRequest.getContent());
noteService.addNote(note); // throws NotAuthorizedException
NoteResponse noteResponse = new NoteResponse();
noteResponse.setContent(note.getContent());
return noteResponse;
}
}
Here is my test class:
#RunWith(PowerMockRunner.class)
public class NoteServiceHelperTest {
String dummyContent = "ABCD";
#InjectMocks
private NoteHelper noteHelper;
#Mock
private NoteService noteService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
#PrepareForTest({NoteHelper.class, ServiceBuilder.class})
public void createNewNoteTest() throws NotAuthorizedException {
noteService = Mockito.mock(NoteService.class);
PowerMockito.mockStatic(ServiceBuilder.class);
PowerMockito.when(ServiceBuilder.getService(NoteService.class))
.thenReturn(noteService);
doNothing().when(noteService).addNote(any(Note.class));
NoteRequest request = new NoteRequest();
request.setContent(dummyContent);
NoteResponse response = noteHelper.createNewNote(request);
assertEquals(response.getContent(), dummyContent);
}
}
From what I read I thought that the call to ServiceBuilder.getService(...) will get replaced and noteService will be using a mocked instance instead of a real instance.
The problem is that this is not happening and the getService(...) method is actually called and eventually fails due to some external system dependencies (ServiceBuilder.getService(...) needs to acquire some database connections and make HTTP calls to other systems before it returns the NoteService instance).
So my question is how can I use power mockito to mock the getService(...) and the noteService.addNote(note) calls ?
Related
I am writing an unit test for method that instantiates final class like this:
public Mono<String> getSecret(String key) {
SecretClientBuilder secretClientBuilder = new SecretClientBuilder();
secretClientBuilder = secretClientBuilder.vaultUrl(keyVaultUrl);
secretClientBuilder = secretClientBuilder.credential(new DefaultAzureCredentialBuilder().build());
SecretClient secretClient = secretClientBuilder.buildClient();
KeyVaultSecret retrievedSecret = secretClient.getSecret(key);
return Mono.just(retrievedSecret.getValue());
}
SecretClient and SecretClientBuilder are imported from azure library. In order to test this, I am trying to use PowerMockito
My approach is to create mock object when new SecretClientBuilder() is called so when that mock object is calling methods such as .vaultUrl() or .credential(), I can make my test to return a mocked objects. Here is my starting code:
#Before
public void before() {
keyVaultService = new KeyVaultServiceImpl(KEY_VAULT_URL);
}
#Test
public void test() throws Exception {
SecretClientBuilder secretClientBuilder = mock(SecretClientBuilder.class);
PowerMockito.whenNew(SecretClientBuilder.class).withNoArguments().thenReturn(secretClientBuilder);
PowerMockito.when(secretClientBuilder.vaultUrl(anyString())).thenReturn(secretClientBuilder);
keyVaultService.getSecret(CLIENT_ID_KEY);
}
However, test fails because when SecretClientBuilder is being instantiated, it does not return the mock object. Instead, it creates a new instance of SecretClientBuilder when SecretClientBuilder secretClientBuilder = new SecretClientBuilder().
How can I instantiate SecretClientBuilder object using PowerMockito? SecretClientBuilder is final class.
Edit:
This is what I am using for class annotations:
#RunWith(PowerMockRunner.class)
#PrepareForTest({KeyVaultService.class, SecretClientBuilder.class})
I tried only using either classes in #PrepareForTest and nothing works with same behavior.
Edit2: I was testing with TestService to see if final was an issue. It was not. Here is my TestService:
public class TestService {
public String test() {
return "actual";
}
and here is my KeyVaultService:
public Mono<String> getSecret(String key) {
TestService testService = new TestService();
System.out.println(testService.test());
...
}
and my test:
#Test
public void test() throws Exception {
TestService mock = mock(TestService.class);
PowerMockito.whenNew(TestService .class).withAnyArguments().thenReturn(mock);
PowerMockito.when(mock.test()).thenReturn("mock");
keyVaultService.getSecret(CLIENT_ID_KEY);//should print "mock"
}
But it prints "actual" meaning mocked object was never created when new TestService(); was called. Is my understanding of PowerMockito and whenNew wrong somewhere?
Found an answer. Leaving this for anybody who is having some issue.
Problem was that I was adding interface class not actual implementation class. Changing #PrepareForTest(KeyVaultService.class) to #PrepareForTest(KeyVaultServiceImpl.class) works.
Here is the class and the method I am trying to unit test.
public abstract class ShowService {
#Resource(name = "blogCoreSolrClient")
private SolrClient blogCoreSolrClient;
protected Show findShow(ClientRegion clientRegion, TargetLocale locale, Integer showId) {
SolrQuery query = new SolrQuery();
query.setQuery("type:" + SolrType.show)
.addFilterQuery(getRegionQuery(clientRegion))
.addFilterQuery(getLanguageFallbackQuery(locale))
.addFilterQuery("show_id:" + showId)
.setRows(1);
QueryResponse response = blogCoreSolrClient.query(query);
List<Show> shows = response.getBeans(Show.class);
if (shows != null && shows.size() > 0) {
return shows.get(0);
}
return null;
}
public static class SyndicatedShow {
#Field("show_id")
public Integer showId;
#Field("path_value")
public String pathValue;
}
}
Here's my Unit test written using Mockito
public class ShowServiceTest {
public final QueryResponse queryResponse = Mockito.mock(QueryResponse.class);
public final SolrClient blogCoreSolrClient = Mockito.mock(SolrClient.class);
public final SolrQuery SolrQuery = Mockito.mock(SolrQuery.class);
private SolrDocumentList solrDocuments = Mockito.mock(SolrDocumentList.class);
private ShowService showService = Mockito.mock(ShowService.class);
#Test
public void findShowTest() {
Mockito.when(blogCoreSolrClient.query(solrQueryCaptor.capture())).thenReturn(queryResponse);
Mockito.when(queryResponse.getResults()).thenReturn(solrDocuments);
Mockito.when(blogCoreSolrClient.query(any())).thenReturn(queryResponse);
ShowService.Show showsResult = ShowService.findShow(ClientRegion.US, TargetLocale.EN_US, 1234);
assertThat(showsResult.pathValue).isEqualTo("shows/test/");
}
}
I am getting Null at blogCoreSolrClient when the code passes to findShow().
Because of that I am getting NullPointerException.
Any suggestions, where I might be going wrong. TIA
There are different problems :
You're mocking the class under test
private ShowService showService = Mockito.mock(ShowService.class);
You don't tell to your ShowService to use the blogCoreSolrClient mock, then the blogCoreSolrClient mock instance is created, but never used.
As you are using IOC to inject the SolrClient (#Resource annotation), you need to inject the mock in your ShowService instance during the test.
There are different solutions, but the more convenient in your case would be to use the Mockito Extension to perform the injection.
Something like :
#ExtendWith(MockitoExtension.class)
public class ShowServiceTest {
#Mock
private SolrClient blogCoreSolrClient;
... // Other mocks
#InjectMocks
private ShowService showService;
#Test
public void findShowTest() {
Mockito.when(blogCoreSolrClient.query(any())).thenReturn(queryResponse);
... // Complete test
}
}
The problem would be that your class under test is an abstract class.
I don't see any abstract method. So, if you really need the class under test to be abstract, then you'll face a technical difficulty with #InjectMocks.
Here are some solutions :
https://tedvinke.wordpress.com/2020/06/22/mockito-cannot-instantiate-injectmocks-field-the-type-is-an-abstract-class/
I've written a class which reads the entire file and returns the content.
class ClassToTest {
public methodToTest(String input) {
return privateMethod(input);
}
private privateMethod(input) {
ClassPathResource classPathResource = new ClassPathResource(input);
IOUtils.toString(classPathResource.getFile());
}
}
Now, inside my test class, I don't want my test to actually read the file from so I'm trying to mock the method classPathResource.getFile() but somehow I'm not able to do so without writing PrepareForTests() and if I do that those test are not counted in JaCoCo.
I've written test case as
#Test
public void test_methodToTest() {
mockStatic(IOUtils.class);
when(IOUtils.toString(any()).thenReturn("DUMMY_STRING");
methodToTesT("file1.txt");
...
}
The problem is IOUtils.toString gets mocked properly but the call classPathResource.getFile() tries to access the file on the disk. For this, I can do this
PowerMockito.whenNew(ClassPathResource.class)
.withAnyArguments().thenReturn(mockedClassPath);
And add annotation to my test class as
#PrepareForTest(ClassToTest.class)
class MyTestClass {
...
}
But now the problem is this test class is skipped from the JACOCO test coverage . How can I write tests for this class?
You can pass a mocked reference into the constructor doing this:
class ClassToTest {
private ClassPathResource classPathResource;
public ClassToTest(ClassPathResource classPathResource) {
this.classPathResource = classPathResource;
}
public methodToTest(String input) {
IOUtils.toString(classPathResource.getFile(input));
}
}
Or you can pass the mocked reference into the method doing this:
class ClassToTest {
public methodToTest(ClassPathResource classPathResource) {
IOUtils.toString(classPathResource.getFile());
}
}
Having to mock a private member should be seen as a code smell and an indication that something is wrong with the current design. Because ClassPathResource is being initialized internal to the subject class it is now tightly coupled to that class. While not entirely impossible to mock it does make testing the class cleanly more difficult. Consider inverting the creation of the class to a delegate as a dependency.
public interface PathResource {
String getFile(String input);
}
This will allow the injection of the dependency
class ClassToTest {
private classPathResource;
public ClassToTest (PathResource resource) {
this.classPathResource = resource;
}
public String methodToTest(String input) {
return privateMethod(input);
}
private String privateMethod(String input) {
return IOUtils.toString(classPathResource.getFile(input));
}
}
and the dependency can be mocked/faked/stubbed when testing.
public void Test() {
//Arrange
//mock creation
PathResource resource = mock(PathResource.class);
String input = "path";
String expected = "expected_output";
//stubbing
when(resource.getFile(input)).thenReturn(expected);
ClassToTest subject = new ClassToTest(resource);
//Act
String actual = subject.methodToTest(input);
//Assert
verify(resource).getFile(input);
assertEquals(expected, actual);
}
in production code the ClassPathResource would be derived from the abstraction
public class ClassPathResource implements PathResource {
//...code removed for brevity
}
and it would be associated with the abstraction at the composition root.
Following the above suggestions would now allow ClassToTest to be tested in isolation without any knock on effects of implementation concerns.
I am trying to test the ClientDetails class below and trying to learn JUnit and Mockito at the same time.
// this is the class I'm trying to test
public class ClientDetails {
#Autowired private IApplicantService<Applicant> applicantService;
#Autowired private ClientDetailsHelpers helpers;
public FullClientDetails getClientDetails(String businessId, boolean isNewClient) {
FullClientDetails fcd = new FullClientDetails();
ClientParams params = new ClientParams();
params.setBusinessId(businessId);
ApplicantId ai = applicantService.retrieveApplicantIdFromBusinessId(params);
Long applicantId = ai.getApplicantId();
params.setApplicantId(applicantId);
Applicant applicant = applicantService.retrieveApplicantDetailsByHerdNumber(params);
helpers.validateRetrievedApplicant(applicant, isNewClient, businessId);
fcd.setApplicant(applicant);
// more method calls that get and assign objects to the fcd object
return fcd;
}
}
// ClientDetailsHelpers.java method that throws exception
public void validateRetrievedApplicant(Applicant applicant, boolean isNewClient, String businessId) {
if (applicant.getApplicantId() == null && !isNewClient) {
throw new ValidationSearchException(businessId);
}
}
// test class
#RunWith(MockitoJUnitRunner.class)
public class ClientDetailsTest {
private final static String BUSINESS_ID = "A1234567";
private final static Long APPLICANT_ID = null;
#InjectMocks
ClientDetails clientDetails;
#Mock ApplicantServiceImpl applicantService;
#Mock ClientDetailsHelpers helpers;
private ApplicantParams params;
private Applicant applicantWithInvalidId = new Applicant();
ApplicantId applicantId = new ApplicantId(APPLICANT_ID, BUSINESS_ID);
#Before
public void before(){
applicantWithInvalidId.setApplicantId(null);
}
#Test(expected = ValidationSearchException.class)
public void testGetFullApplicationDetails(){
when(applicantService.retrieveApplicantIdFromBusinessId(Mockito.any(ApplicantParams.class))).thenReturn(applicantId);
when(applicantService.retrieveApplicantDetailsByHerdNumber(Mockito.any(ApplicantParams.class))).thenReturn(applicantWithInvalidId);
FullClientDetails fcd = clientDetails.getFullClientDetails(BUSINESS_ID , false);
}
}
In my test class I create some mock objects, including an ApplicantId object to be returned when applicantService.retrieveApplicantIdFromBusinessId() is called and Applicant object with is applicantId attribute set to null to be return when applicantService.retrieveApplicantDetailsByHerdNumber() is called.
The function ClientDetailsHelper.validateRetrievedApplicant() should throw an exception if Applicant.getApplicantId() returns a null and if the boolean isNewClient is set to false however it doesn't seem to be happening in the test, it throws no exception and the #Test fails.
My best guess is that I am not using when().thenReturn() to correctly return the Applicant and ApplicantId objects I have created and instead another Applicant object is getting passed to validateRetrievedApplicant() and returning and applicantId of 0 when it gets to the validation method.
Any suggestions? Thanks!
Your code is not throwing an exception because there is nowhere in the code you are testing that throws that exception. I assume your exception is thrown within the ClientDetailsHelpers class but you are mocking this class so it will not call the actual code and so no exception will be thrown.
You need to think about what you want to test. Do you want to test the ClientDetails class in isolation as a unit? In which case you don't need to worry about the exception being thrown since its not part of the functionality of that class.
The second option is that you want to do more of an integration test where you pull in an actual ClientDetailsHelpers class but in order to do this you will need to include some configuration in your test to make sure that this bean is available to the test Spring context. You can do this using a Spring4JunitRunner instead of the Mockito one and then pulling in a configuration class with a component scan for your ClientDetailsHelpers class using the #ContextConfiguration(MyConfig.class) annotation on your test class where MyConfig is the relevant Spring config class.
I am new to GWT MVP Pattern with Activities and Places with the combination of GIN. I have started attempting to write a JUnit test case for my GWT project using Mockito. A lot of blogs suggested that I do not use GWT Test Case because of its performance so I planned on sticking to Mockito. I am writing a test case for one of the Presenters. Since I am using GIN to create instance for most of the things in my Presenter I have to mock my Gin Injector object. My Junit Test Case is not allowing me to mock the Gin injector. I read somewhere that we cannot use Gin in the Junit Test Case instead we have to go with Guice. My question is that how do I mock my Gin injector using Mockito? I found some Test Case which used the exact same pattern that I did for my project except that they used Client Factory instead. I have failed in replacing the Client factory with GIN in the test case. The code that I found online is as follows and I have to replace Client Factory with GIN injector in my Test Case.
#RunWith(MockitoJUnitRunner.class)
public class ContactListActivityTest {
#Mock
private IClientFactory clientFactoryMock;
#Mock
private PlaceController placeControllerMock;
#Mock
private IContactListView contactListViewMock;
#Mock
private AcceptsOneWidget acceptsOneWidgetMock;
#Mock
private IContactServiceAsync contactServiceAsyncMock;
#Mock
private EventBus eventBusMock;
private List<Contact> contacts;
private Contact contact1;
private Contact contact2;
#SuppressWarnings("unchecked")
#Before
public void setUp() throws Exception {
when(clientFactoryMock.getPlaceController()).thenReturn(placeControllerMock);
when(clientFactoryMock.getContactListView()).thenReturn(contactListViewMock);
when(clientFactoryMock.getContactService()).thenReturn(contactServiceAsyncMock);
Answer<Void> answer = new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
AsyncCallback<List<Contact>> asyncCallback = (AsyncCallback<List<Contact>>) args[0];
contact1 = new Contact();
contact1.setFirstName("Kai");
contact1.setLastName("Toedter");
contact1.setEmail("kai#toedter.com");
contact2 = new Contact();
contact2.setFirstName("Kai2");
contact2.setLastName("Toedter2");
contact2.setEmail("kai2#toedter.com");
final List<Contact> contacts2 = new ArrayList<Contact>();
contacts2.add(contact1);
contacts2.add(contact2);
asyncCallback.onSuccess(contacts2);
return null;
}
};
doAnswer(answer).when(contactServiceAsyncMock).getAllContacts(any(AsyncCallback.class));
// set the real contacts object, when clientFactory.setContacts is
// called
Answer<Void> setContactsAnswer = new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
contacts = (List<Contact>) invocation.getArguments()[0];
// System.out.println("answer() to setContacts(): " + contacts);
return null;
}
};
doAnswer(setContactsAnswer).when(clientFactoryMock).setContacts(any(List.class));
// Return the real contacts object, when clientFactory.getContacts is
// called
Answer<List<Contact>> getContactsAnswer = new Answer<List<Contact>>() {
#Override
public List<Contact> answer(InvocationOnMock invocation) throws Throwable {
return contacts;
}
};
doAnswer(getContactsAnswer).when(clientFactoryMock).getContacts();
}
#Test
public void testGotoPlace() {
ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(null), clientFactoryMock);
ContactPlace contactPlace = new ContactPlace("kai#toedter.com");
contactListActivity.goTo(contactPlace);
verify(placeControllerMock).goTo(contactPlace);
}
#Test
public void testStartWithEmptyToken() {
clientFactoryMock.setContacts(null); // force RCP
ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(""), clientFactoryMock);
contactListActivity.start(acceptsOneWidgetMock, eventBusMock);
verify(contactListViewMock).setPresenter(contactListActivity);
verify(contactListViewMock).initialize(contacts);
}
#Test
public void testStartWithToken() {
String token = "kai#toedter.com";
clientFactoryMock.setContacts(null); // force RCP
ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(token), clientFactoryMock);
contactListActivity.start(acceptsOneWidgetMock, eventBusMock);
verify(contactListViewMock).setPresenter(contactListActivity);
verify(contactListViewMock).initialize(contacts);
verify(contactListViewMock).selectInitialContact(contact1);
verify(eventBusMock).fireEvent(any(ContactViewEvent.class));
}
#Test
public void testMayStop() {
ContactListActivity contactListActivity = new ContactListActivity(new ContactPlace(null), clientFactoryMock);
contactListActivity.start(acceptsOneWidgetMock, eventBusMock);
contactListActivity.mayStop();
verify(contactListViewMock).setPresenter(null);
}
#Test
public void clientFactoryTest() {
List<Contact> testList = new ArrayList<Contact>();
clientFactoryMock.setContacts(testList);
Assert.assertNotNull(clientFactoryMock.getContacts());
}
}
Please Help.
If your code depends on the Ginjector, then you have a problem: you're not injecting direct dependencies. If you need a factory of objects, inject a Provider.
But in your case, IClientFactory also serves as a shared state, a value holder or local cache for a List<Contact>; which means IClientFactory violates the single responsibility principle.
So, first extract the local cache responsibility into its own object (e.g. a ContactListCache object, or a more generic ValueHolder<List<Contact>>) then inject an instance of that object.
And of course, inject the PlaceController, view and GWT-RPC service directly.
But actually, I'd go farther and refactor the code to extract the retrieve from cache or ask the server responsibility into its own ContactListHolder object (or, as you're using GWT-RPC, you could implement the IContactServiceAsync interface as a wrapper around the one generated by GWT.create() and that adds the caching behavior; see http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html for some inspiration). That would simplify the activity's code a lot.
As a side note, this code probable makes too much use of mocking: why not using the real PlaceController (and spy()ing its goTo(Place) method) and a SimpleEventBus or CountingEventBus?
What I have done is to use GwtMockito which is an extension of Mockito. In the only one class that I use my injector, my test looks like this
#RunWith(GwtMockitoTestRunner.class)
public class AppControllerTest {
AppController controller;
#Mock
EventBus eventBus;
#Mock
AppInjector injector;
#Before
public void setUp() throws Exception {
}
#Test
public void shouldUseInjector() throws Exception {
// Given
controller = new AppController(eventBus, injector);
// When
controller.go();
// Verify
verify(injector).mainPresenter();
}
}