I'm new to writing tests in Java and trying to learn Mockito.
This is part of the class I want to test.
public class ExamRepository implements IExamRepository {
private static final Logger LOGGER = LogManager.getLogger(ExamRepository.class);
private IStudentRepository studentRepository = new StudentRepository();
private EntityManager entityManager;
public ExamRepository() {
entityManager = EntityController.getEntityManager();
}
public ExamRepository(EntityManager entityManager){
this.entityManager = entityManager;
}
// Get all exam skeletons from the DB
#Override
public List<ExamSkeleton> getAllSkeletons() {
try {
TypedQuery<ExamSkeleton> query = entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class);
return query.getResultList();
} catch (IllegalArgumentException exception) {
LOGGER.error(exception);
}
return Collections.emptyList();
}
}
This is the actual test I wrote, I have a feeling the error:
Argument passed to verify() is of type ExamRepository and is not a mock!
Is occurring because of this line:
examRepository = new ExamRepository(entityManager);
However I am uncertain as to how to rewrite it. I am also not sure what else I should be testing for except for the fact that it ran once.
public class ExamRepositoryTest {
#InjectMocks
private ExamRepository examRepository;
#Mock
private EntityManager entityManager;
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Test
public void canGetAllSkeletons(){
examRepository = new ExamRepository(entityManager);
List<ExamSkeleton> examSkeletons = new ArrayList<>();
examSkeletons.add(new ExamSkeleton());
examSkeletons.add(new ExamSkeleton());
TypedQuery query = mock(TypedQuery.class);
when(entityManager.createQuery(anyString(), Matchers.anyObject())).thenReturn(query);
when(query.getResultList()).thenReturn(examSkeletons);
verify(examRepository, times(1)).getAllSkeletons();
}
}
Hope you guys can put me on the correct track!
Use it like this:
#Test
public void canGetAllSkeletons(){
examRepository = new ExamRepository(entityManager);
List<ExamSkeleton> expected = new ArrayList<>();
expected.add(new ExamSkeleton());
expected.add(new ExamSkeleton());
TypedQuery query = mock(TypedQuery.class);
when(entityManager.createQuery(anyString(), anyObject())).thenReturn(query);
when(query.getResultList()).thenReturn(expected);
List<ExamSkeleton> result = examRepository.getAllSkeletons();
assertEquals(expected, result);
}
Your idea was almost correct, but instead of verifying a call, you just need to do the actual invocation of examRepository.getAllSkeletons() in your test and check the result against your expected return value for the TypedQuery.
And because you can only get the correct result list if your previous mocking steps worked, you don't need to verify any invocation on the EntityManager mock.
Related
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 am trying to write a "simple" unit test. Mockito however always tells me there is an UnfinishedStubbingException.
The code line Mockito is exposing as culprit is the following:
when(myServiceIdFactory.get(any())).thenReturn((SortedSet<MyServiceId>) Set.of(emptyId));
Here is the whole unit test code
#SpringBootTest
#RunWith(SpringRunner.class)
public class MyServiceIdProcessorTest {
#Autowired
private MyServiceIdProcessor myServiceIdProcessor;
#MockBean
private MyServiceIdFactory myServiceIdFactory;
#Test
public void shouldFilterProductsWithNoId() {
Product productWithNoId = new Product();
MyServiceId emptyId = new MyServiceId();
when(myServiceIdFactory.get(any())).thenReturn((SortedSet<MyServiceId>) Set.of(emptyId));
CatalogDTO catalogDTO = new CatalogDTO();
Envelope<CatalogDTO, Product> envelopeToTest = Envelope.products(List.of(productWithNoId));
Envelope returnedEnvelope = myServiceIdProcessor.enrichCatalog(envelopeToTest);
assertThat(returnedEnvelope.getProducts()).hasSize(0);
}
}
The problem was the following cast exception:
when(myServiceIdFactory.get(any())).thenReturn((SortedSet<MyServiceId>) Set.of(emptyId));
Set.of(foo) can't be casted to a SortedSet. The exception however seemed to be swallowed and overwritten by Mockito
Try to spy() the MyServiceIdFactory before define the bahavoir
#Test
public void shouldFilterProductsWithNoId() {
// Arrange
Product productWithNoId = new Product();
MyServiceId emptyId = new MyServiceId();
MyServiceIdFactory spyMyServiceIdFactory = spy(myServiceIdFactory);
SortedSet<MyServiceId> set = (SortedSet<MyServiceId>) Set.of(emptyId);
doReturn(set).when(spyMyServiceIdFactory).get(any());
CatalogDTO catalogDTO = new CatalogDTO();
Envelope<CatalogDTO, Product> envelopeToTest = Envelope.products(List.of(productWithNoId));
// Act
Envelope returnedEnvelope = spyMyServiceIdFactory.enrichCatalog(envelopeToTest);
// Assert
assertThat(returnedEnvelope.getProducts()).hasSize(0);
}
I have the following code in my Java class in a Spring Boot (v. 2.2.1.RELEASE) application:
#Inject
private JdbcTemplate jdbcTemplate;
#Inject
private MyRowCallbackHandler myRowCallbackHandler;
public void myMethod() {
jdbcTemplate.query(MY_QUERY, myRowCallbackHandler);
}
The JDBC template object is an implementation of org.springframework.jdbc.core.JdbcTemplate and the handler is an implementation of org.springframework.jdbc.core.RowCallbackHandler.
With JUnit version 4 and Mockito, can I mimic the retrieval of one or more rows from a database by the query method, thus calling the handler's processRow() method?
Thanks for any assistance.
I ran into this problem in my own code, thought I'd share the solution here, even though it's slightly different than the situation above as I mock the jdbcTemplate as well.
#InjectMocks
private JdbcOperationRepository jdbcOperationRepository;
#Mock
private NamedParameterJdbcTemplate mockJdbcTemplate;
#Test
public void testMyResults() {
final ResultSet mockResult1 = mock(ResultSet.class);
when(mockResult1.getString(MY_COLUMN)).thenReturn(value);
// ... other when statements to mock the returned data
doAnswer(invocation -> {
RowCallbackHandler callbackHandler = invocation.getArgument(2);
callbackHandler.processRow(mockResult1);
callbackHandler.processRow(mockResult2);
return null;
}).when(mockJdbcTemplate).query(any(), any(), any(RowCallbackHandler.class));
}
I was struggling with the same problem. First, you have to keep in mind that you can mock almost anything in spring boot using Junit tests.
I am writing the solution in a generalized pattern so that everyone can get an idea how it gets implemented and used.
Suppose, we have a function implemented in our BookService.java class:
#Service
public class BookService {
#Inject
private NamedParameterJdbcOperations jdbcTemplate;
#Inject
private FileHelper fileHelper;
public List<BookDTO> getBooks(Long libraryId){
String sql = fileHelper.getFileContents("SQL_FILE_PATH");
Map<String, Object> parameterMap = new HashMap<>();
if(libraryId!=null){
parameterMap.put("libraryId", libraryId);
}
List<BookDTO> books = new ArrayList<>();
jdbcTemplate.query(sql, parameterMap, rs -> {
BookDTO book = new BookDTO();
book.setId(rs.getLong("id"));
book.setName(rs.getString("name"));
if(rs.getObject("librarian") != null){
book.setLibrarian(rs.getString("librarian"));
}
books.add(book);
});
return books;
}
}
Now, we want to mock the functionality of the jdbcTemplate.query() method for the above service class.
Our test should be written in this pattern:
public class BookServiceMockTest {
#Mock
private NamedParameterJdbcOperations jdbcTemplate;
#Mock
private FileHelper fileHelper;
private BookService mockBookService;
#Before
public void setup(){
mockBookService = new BookService();
// using reflectionUtils setFields of the fileHelper and jdbcTemplate.
// ....
}
#Test
public void getBooksTest(){
when(fileHelper.getFileContents("SQL_FILE_PATH")).thenReturn("SOME SQL");
doAnswer(invocation -> {
// we are going to mock ResultSet class.
ResultSet rs = Mockito.mock(ResultSet.class);
when(rs.getLong("id")).thenReturn(1L);
when(rs.getString("name")).thenReturn("Game of Thrones");
// this will mock the if() statement
when(rs.getObject("librarian")).thenReturn("John Doe");
// this will mock the actual get statement call on getString() inside the if statement
when(rs.getString("librarian")).thenReturn("John Doe");
// the argument index is important here.
// we are doing getArgument(2).
// This means the third parameter passed in the jdbcTemplate.query(Param0, Param1, Param2) in the BookService.getBooks() function.
RowCallbackHandler rch = (RowCallbackHandler) invocation.getArgument(2);
// as we are mocking only one row..
rch.processRow(rs);
/* // if we wanter two or more results:
when(rs.getLong("id")).thenReturn(1L).thenReturn(2L);
when(rs.getString("name")).thenReturn("Game of Thrones").thenReturn("Dance of the Dragon");
int n = 2; // no of rows..
for(int i=0; i<n; i++){
rch.processRow(rs);
}
*/
return null;
})
// the parameters used here are important. Any mismatch will result in unsuccessful.
.when(jdbcTemplate).query(eq("SOME SQL"), anyMap(), any(RowCallbackHandler.class));
List<BookDTO> books = mockBookService.getBooks(anyLong());
verify(jdbcTemplate, times(1)).query(eq("SOME SQL"), anyMap(), any(RowCallbackHandler.class));
assertThat(books).hasSize(1);
}
}
I hope this answered what you were looking for!
I unable to mock an instance of a Class which is being created inside the method which I am trying to test. Below is an example to illustrate the issue.
Class and Method Being tested:
// class being used in the class to be tested
public class SomeOtherClass{
public ResponseObject addObject(Request dtoObject){
/// Some business logic goes here
return reponseObject;
}
}
// Class to be tested
public class ClassToBeTested {
public ClassToBeTested() {}
public void myMethodToBeTested() {
SomeOtherClass otherClassObject = new SomeOtherClass();
// Here I want mock the otherClassObject and also addObject method
// Eventhoug I mocked it seems to me that as otherClassObject is being created here locally
// I am unable to mock it.
ReponseObject reponseObject = otherClassObject.addObject(dtoObject);
// do some other stuff using the reponseObject
}
}
Test Class:
public class TestClassToBeTested {
#Tested private ClassToBeTested classBeingTested;
#Injectable SomeOtherClass innerSomeOtherClass;
RequestObject myRequestObject = new RequestObject();
myRequestObject.setSomevalue1("1");
myRequestObject.setSomevalue2("2");
ResponseObject myMockResponseObject = new ResponseObject();
myMockResponseObject.setResultCode(SUCCESS);
#Test
public void shouldTestSomething() {
new NonStrictExpectations(){{
// Here I am returning the mocked response object.
SomeOtherClass.addObject((SomeOtherClass)any);
result =myMockResponseObject;
}};
classBeingTested.myMethodToBeTested();
// ...
}
}
I mocked the SomeOtherClass and its method but no luck, not sure the proper way to mock it using JMockit.
SomeOtherClass & its method addObject
Even though I mocked it in the Test class, but it gets cleared in the method to be tested. I found similar question being asked HERE, but the solution uses some other unit test framework Mockito. I am struggling to find similar solution using JMokcit. Could any one help me to find the solution for this?
Below is my updated code sample
Class and Method Being tested:
// This is the class to be tested
public class MyMainClass {
public ResponseObject addItem(ProductList products) {
ResponseObject responseObject = new ResponseObject();
OtherService otherService = new OtherService();
List<Product> productList = new ArrayList<Product>();
productList = products.getProducts();
for (int i = 0; i < productList.size(); i++) {
Product product = otherService.addProduct(productList.get(i));
System.out.println("model.Product " + product.getName() + " added
successfully");
}
responseObject.setResponseCode("1");
responseObject.setResponseMessage("Success");
return responseObject;
}
}
// Some other service internally used by MyMainClass
public class OtherService implements IService{
public Product addProduct(Product product){
// Some business logic to process the product
System.out.println("Adding product :"+product.getName());
return product;
}
}
// Interface implemented by OtherService
public interface IService {
Product addProduct(Product product);
}
// Sample ResponseObject class
public class ResponseObject {
String responseCode;
String responseMessage;
public String getResponseMessage() {
return responseMessage;
}
public void setResponseMessage(String responseMessage) {
this.responseMessage = responseMessage;
}
public String getResponseCode() {
return responseCode;
}
public void setResponseCode(String responseCode) {
this.responseCode = responseCode;
}
}
Test Class:
public class MyMainClassTest {
#Tested
MyMainClass myMainClass;
#Mocked
IService otherService;
private List<Product> myProducts = new ArrayList<Product>();
#Before
public void init(){
Product product1 = new Product();
product1.setName("Test1");
product1.setPid(1);
product1.setPrice(100.00);
myProducts.add(product1);
Product product2 = new Product();
product2.setName("Test2");
product2.setPid(2);
product2.setPrice(200.00);
myProducts.add(product2);
}
#Test
public void addItem_Test() throws Exception{
myMainClass = new MyMainClass();
new NonStrictExpectations(){{
otherService.addProduct((Product)any);
returns(myProducts.get(0));
}};
ProductList productList = new ProductList();
productList.setProducts(myProducts);
ResponseObject responseObject = myMainClass.addItem(productList);
Assert.assertEquals(responseObject.getResponseMessage(),"Success");
}
}
After trying and analyzing the problem I found the what went wrong. I will update the solution in the answer section so that it would be helpful others also.
Thanks.
You simply use #Mockedfor that. Check the JMockit tutorial or the API documentation, there are plenty of examples.
After trying and debugging again I found what was wrong. What I was doing wrong is mocking the interface (IService) and hence it was not working. When I changed it to mock the implemented class (OtherService) then it worked properly.
So in the Test class I replaced
#Mocked IService otherService;
with
#Mocked OtherService otherService;
After this change my problem got resolved.
Thanks
I have a lot of code like the sample below that I need to test with Mockito.
return entityManager
.createNamedQuery("queryName", Type.class)
.setParameter("foo", "fish")
.setParameter("bar", 42)
.getSingleResult();
I have already injected a mocked EntityManager and have it return a mocked TypedQuery, etc. The problem is that I need to specify a rule like the following for every method in TypedQuery in order to have the test run successfully without NullPointerExceptions.
when(mockedTypedQuery.setParameter(any(String.class), any(Object.class)))
.thenReturn(mockedTypedQuery);
Is there a more efficient way?
What I did in that case, was totally inspired by this post: http://geeks.autotrader.co.uk/2014/03/mocking-fluent-interfaces-with-mockito.html
I had the following service:
public class TestService {
public TypedQuery typedQuery;
public List test(){
final TypedQuery typedQuery1 = typedQuery.setParameter("a", "a");
return typedQuery1.setParameter("b", "b").getResultList();
}
}
And my test case was:
#RunWith(MockitoJUnitRunner.class)
public class ChainMethodsMockTest {
TypedQuery mockedTypedQuery = fluentMock(TypedQuery.class);
#InjectMocks
TestService testService;
#Test
public void testMockito(){
final ArrayList value = new ArrayList();
value.add("a");
value.add("b");
Mockito.when(mockedTypedQuery.getResultList()).thenReturn(value);
final List test = testService.test();
Assert.assertEquals(2, test.size());
}
public static <T> T fluentMock(final Class<T> type) {
return Mockito.mock(type, Mockito.withSettings().defaultAnswer(
new ReturnsEmptyValues() {
#Override
public Object answer(InvocationOnMock invocation) {
Object defaultReturnValue = super.answer(invocation);
if (type.equals(invocation.getMethod().getReturnType())) {
return invocation.getMock();
} else {
return defaultReturnValue;
}
}
}));
}
}
fluentMock method that you can share and reuse among your project(s).