I'm trying to mock Model.finder to test my service, but it seems mockito isn't being injected for some reason and I cannot figure out why. Please help.
public static Result deals() {
List<Product> finder = new Model.Finder<Long, Product>(Long.class, Product.class).all();
JsonNode jsonNode = Json.toJson(finder);
return ok(Json.stringify(jsonNode));
}
And here's my test
#Mock
private Model.Finder finder;
#Before
public void setUp() throws Exception {
initMocks(this);
start(fakeApplication());
Product product = new Product();
product.id = 1L;
product.title = "Milk";
List<Product> products = Arrays.asList(product);
when(finder.all()).thenReturn(products);
}
#Test
public void shouldGetDeals() {
Result result = routeAndCall(fakeRequest(GET, "/products"));
assertThat(status(result), is(200));
String deals = contentAsString(result);
assertThat(deals, containsString("Milk"));
}
So, the result is that Model.Finder returns 0 because the mock is not invoked. I'm not sure if this is how you mock in Play 2.1?
Your deals() method is making a new Finder, rather than using the mock one that you created. You're going to need to refactor your code a little, to make it more testable. You may want to read https://code.google.com/p/mockito/wiki/MockingObjectCreation for a couple of ideas on how you could do this.
Related
I am new in unit testing and use JUnit in my Java (Spring Boot) app. I sometimes need to test update methods, but when I search on the web, there is not a proper example or suggestion. So, could you please clarify me how to test the following update method? I think this may require a different approach than testing void. I also thought that while testing first mocking the record and then update its field and then update. Finally retrieve the record again and compare the updated properties. But I think there may be more proper approach than this inexperienced one.
public PriceDTO update(UUID priceUuid, PriceRequest request) {
Price price = priceRepository
.findByUuid(priceUuid)
.orElseThrow(() -> new EntityNotFoundException(PRICE));
mapRequestToEntity(request, price);
Price updated = priceRepository.saveAndFlush(price);
return new PriceDTO(updated);
}
private void mapRequestToEntity(PriceRequest request, Price entity) {
entity.setPriceAmount(request.getPriceAmount());
// set other props
}
You would need to do something along the following lines:
public class ServiceTest {
#Mock
private PriceRepository priceRepository;
(...)
#Test
public void shouldUpdatePrice() throws Exception {
// Arrange
UUID priceUuid = // build the Price UUID
PriceRequest priceUpdateRequest = // build the Price update request
Price originalPrice = // build the original Price
doReturn(originalPrice).when(this.priceRepository).findByUuid(isA(UUID.class));
doAnswer(AdditionalAnswers.returnsFirstArg()).when(this.priceRepository).saveAndFlush(isA(Price.class));
// Act
PriceDTO updatedPrice = this.service.update(priceUuid, priceUpdateRequest);
// Assert
// here you need to assert that updatedPrice is as you expect according to originalPrice and priceUpdateRequest
}
}
You need to mock the behavior of the class object priceRepository.
So you will have to write something like below to begin :
// priceRepository should be mocked in the test class
Mockito.when(priceRepository.findByUuid(any(UUID.class))).thenReturn(new Price());
So if your only intention is to verify if you called save, then something like this is probably what you are looking for:
#ExtendWith(MockitoExtension.class)
public class ServiceTest {
#Mock
private PriceRepository priceRepository;
#InjectMocks
private Service service;
#Test
public void update() throws Exception {
// Given
Price price = new Price();
price.setUid(UUID.randomUUID());
price.setPriceAmount(100);
when(priceRepository.findByUid(price.getUid()))
.thenReturn(price);
ArgumentCaptor<Price> priceArgument =
ArgumentCaptor.forClass(Price.class);
when(incidentRepository.saveAndFlush(priceArgument.capture()))
.thenAnswer(iom -> iom.getArgument(0));
// When
PriceRequest priceRequest = new PriceRequest();
priceRequest.setPriceAmount(123);
PriceDTO updatedPrice = this.service.update(price.getUid(), priceUpdateRequest);
// Then
assertThat(priceArgument.getValue().getPriceAmount())
.isEqualTo(123);
}
}
I have such method in my service layer:
public Long calculateItemsCostInShoppingCart(Long shoppingCartId) {
List<Item> items = shoppingCartRepository.findAllItems(shoppingCartId);
Long cost = 0L;
for (Item item : items) {
cost += item.getPrice();
}
return cost;
}
And I need to test calculation of summary cost of all items in list. I was thought about mockito, but it didn't work out cause mockito just create stubs, I need real entrance data and result based on them. How can do it?
// create mock
ShoppingRepository mock = mock(ShoppingRepository.class);
// define return value for method findAllItems()
when(mock.findAllItems()).thenReturn(listOf(...));
Here is an example how you can test it with Mockito:
public class SomeCalculatorTest {
#Mock
private ShoppingCartRepository shoppingCartRepository;
#InjectMocks
private SomeCalculator someCalculator = new SomeCalculator();
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testEmptyItemsList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(new ArrayList<>());
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(0L));
}
#Test
public void testOneItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(25L));
}
#Test
public void testTwoItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L), new ItemImpl(12L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(37L));
}
}
Assuming that you are developing a Java web application which runs on a application server another option might be to use Arquillian (http://arquillian.org/). In a nutshell, Arquillian is a framework which allows you to test you logic in environment it will run. But it might be some work to integrate Arquillian into your project. We are using Arquillian in several projects and it works well so far. Even the Persistence module which is an Alpha version works well.
And I need to test calculation of summary cost of all items in list.
In this case, you have to isolate the shoppingCartRepository dependency that doesn't perform any calculation.
I need real entrance data and result based on them. How can do it?
It describes an integration test. In this case, don't use Mockito.
To unit test :
You have to mock the dependency and you also need a way to set it in the instance of the class under test.
A constructor is often a fine way (let calling the class under test MyService):
public MyService(ShoppingCartRepository shoppingCartRepository){
this.shoppingCartRepository = shoppingCartRepository;
}
Then, in the test you should mock ShoppingCartRepository, record a behavior for findAllItems() and pass the mock in the constructor of MyService.
#Mock
private ShoppingCartRepository shoppingCartRepositoryMock;
#Test
public void calculateItemsCostInShoppingCart(){
Long cartId = Long.valueOf(123);
// set the dependency
MyService myService = new MyService(shoppingCartRepositoryMock);
// create the mock
Mockito.when(shoppingCartRepositoryMock.findAllItems(cartId))
.thenReturn(createMockedItems());
//action
Long actualCost = myService.calculateItemsCostInShoppingCart(cartId);
// assertion
Assert.assertEquals(expectedCost, actualCost);
}
private List<Item> createMockedItems() { ... }
You can use Rest assured library for test
get Rest assured response Object, and call method for method object of list.
#BeforeClass
public static void init() {
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8080;
}
#Test
public void testUserRegistration() {
Response response =
RestAssured
.given()
.get(URL_LOGIN)
.then()
.assertThat()
.statusCode(200);
Assert.assertThat(200, Matchers.is(200));
Assert.assertThat(response.getStatusCode(), Matchers.is(200));
}
At first I want to sorry for my english.
I started to make some unit tests (i've never done this before, i'm a new guy in programming).
I have to test simple adding product to database (DynamoDB) method using mockito.verify but I have
"Wanted but not invoked. Actually, there were zero interactions with this mock."
Error and I don't know what to do.
This is my method code (in KitchenService class):
public Product addProduct(Product content) {
ObjectMapper objectMapper = new ObjectMapper();
String mediaJSON = null;
String authorJSON = null;
String productKindsJSON = null;
try {
mediaJSON = objectMapper.writeValueAsString(content.getMedia());
authorJSON = objectMapper.writeValueAsString(content.getAuthor());
productKindsJSON = objectMapper.writeValueAsString(content.getProductKinds());
} catch (JsonProcessingException e) {
logger.log(e.getMessage());
}
Item item = new Item()
.withPrimaryKey("id", UUID.randomUUID().toString())
.with("name", content.getName())
.with("calories", content.getCalories())
.with("fat", content.getFat())
.with("carbo", content.getCarbo())
.with("protein", content.getProtein())
.with("productKinds", productKindsJSON)
.with("author", authorJSON)
.with("media", mediaJSON)
.with("approved", content.getApproved());
Item save = databaseController.saveProduct(PRODUCT_TABLE, item);
logger.log(save + " created");
return content;
}
And this is test code:
#Test
public void addProduct() throws Exception {
KitchenService instance = mock(KitchenService.class);
Product expectedProduct = new Product();
expectedProduct.setName("kaszanka");
expectedProduct.setCalories(1000);
expectedProduct.setFat(40.00);
expectedProduct.setCarbo(20.00);
expectedProduct.setProtein(40.00);
expectedProduct.setProductKinds(Collections.singletonList(ProductKind.MEAT));
expectedProduct.setApproved(false);
Author expectedAuthor = new Author();
expectedAuthor.setId("testID");
expectedAuthor.setName("Endrju Golota");
expectedProduct.setAuthor(expectedAuthor);
Media expectedMedia = new Media();
expectedMedia.setMediaType(MediaType.IMAGE);
expectedMedia.setName("dupajasia");
expectedMedia.setUrl("http://blabla.pl");
expectedProduct.setMedia(expectedMedia);
verify(instance, times(1)).addProduct(expectedProduct);
}
This is what I got after test:
Wanted but not invoked:
kitchenService.addProduct(
model.kitchen.Product#a0136253
);
-> at service.kitchen.KitchenServiceTest.addProduct(KitchenServiceTest.java:80)
Actually, there were zero interactions with this mock.
Can someone tell me what im doing wrong?
What you should mock and verify is the databaseController dependency:
#Test
public void addProduct() throws Exception {
KitchenService instance = new KitchenService(); // you should create the class under test
DatabaseController controllerMock = mock(DatabaseController.class); // mock the controller
instance.setController(controller); // inject the mock
...
// Act
instance.addProduct(expectedProduct);
// Assert
verify(controller).saveProduct(Mockito.eq(PRODUCT_TABLE), Mockito.any(Item.class));
}
You should verify that the database is called within the service.. checking that it was invoked with any Item object should be enough.
Mocking is a tool that you only use for dependencies of the class that is being tested.
It appears that your test does not care about the Author, Media, and Product objects,
these are just dependencies of the method you want to test;
mock them.
Organization will greatly help your test;
do something like this:
public class TestKitchenService
{
private static String VALUE_PRODUCT_NAME = "VALUE_PRODUCT_NAME";
... use constants for other values as well. The value of the constant does not matter.
#InjectMocks
private KitchenService classToTest;
private InOrder inOrder;
#Mock
private Author mockAuthor;
#Mock
private DatabaseController mockDatabaseController;
#Mock
private Logger mockLogger;
#Mock
private Media mockMedia;
#Mock
private Product mockProduct;
#After
public void afterTest()
{
inOrder.verifyNoMoreInteractions();
verifyNoMoreInteractions(mockAuthor);
verifyNoMoreInteractions(mockDatabaseController);
verifyNoMoreInteractions(mockLogger);
verifyNoMoreInteractions(mockMedia);
verifyNoMoreInteractions(mockProduct);
}
#Before
public void beforeTest()
{
MockitoAnnotations.initMocks(this);
doReturn(mockAuthor).when(mockProduct).getAuthor();
doReturn(mockMedia).when(mockProduct).getMedia();
doReturn(VALUE_PRODUCT_NAME).when(mockProduct).getName();
doReturn(Collections.singletonList(ProductKind.MEAT)).when(mockProduct).getProductKinds();
... doReturns for the other product values.
inOrder = inOrder(
mockAuthor,
mockDatabaseController,
mockLogger,
mockMedia,
mockProduct);
ReflectionTestUtils.setField(
classToTest,
"databaseController",
mockDatabaseController);
ReflectionTestUtils.setField(
classToTest,
"logger",
mockLogger);
}
#Test
public void addProduct_success()
{
final Product actualResult;
actualResult = classToTest.addProduct(mockProduct);
assertEquals(
mockProduct,
actualResult);
inOrder.verify(mockProduct).getMedia();
inOrder.verify(mockProduct).getAuthor();
inOrder.verify(mockProduct).getProductKinds();
inOrder.verify(mockProduct).getName();
... inOrder.verify for the other product values.
inOrder.verify(mockDatabaseController).saveProduct(
eq(PRODUCT_TABLE),
any(Item.class));
}
}
The only things that should be mocked -- if anything -- are the ObjectMapper and databaseController. One only mocks collaborator objects, and almost never the system/class under test (very rare cases exist for "spying" on the SUT). And depending on what the ObjectMapper is and how transparent it's operation is, you may not really want to even mock that. Furthermore, as your implementation code is written instantiating the ObjectMapper by directly calling a constructor, you can't even mock it.
While I love the use of Mockito and mock objects, sometimes it is worthwhile to simply test with as many real objects as possible. This is especially true when your collaborators are simple, straightforward, have no side effects, and don't require complex initialization or setup. Only use mocks when it simplifies the test setup or verification.
I was playing with org.springframework.data.jpa.domain.Specifications, it's just a basic search :
public Optional<List<Article>> rechercheArticle(String code, String libelle) {
List<Article> result = null;
if(StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(libelle)){
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
}else{
if(StringUtils.isNotEmpty(code)){
result= articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)));
}else{
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteLibelle(libelle)));
}
}
if(result.isEmpty()){
return Optional.empty();
}else{
return Optional.of(result);
}
}
And that's actually working fine but I'd like to write unit tests for this method and I can't figure out how to check specifications passed to my articleRepository.findAll()
At the moment my unit test looks like :
#Test
public void rechercheArticle_okTousCriteres() throws FacturationServiceException {
String code = "code";
String libelle = "libelle";
List<Article> articles = new ArrayList<>();
Article a1 = new Article();
articles.add(a1);
Mockito.when(articleRepository.findAll(Mockito.any(Specifications.class))).thenReturn(articles);
Optional<List<Article>> result = articleManager.rechercheArticle(code, libelle);
Assert.assertTrue(result.isPresent());
//ArgumentCaptor<Specifications> argument = ArgumentCaptor.forClass(Specifications.class);
Mockito.verify(articleRepository).findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
//argument.getValue().toPredicate(root, query, builder);
}
Any idea?
I was having almost the same problems as you had, and I changed my class that contains Specifications to be an object instead of just one class with static methods. This way I can easily mock it, use dependency injection to pass it, and test which methods were called (without using PowerMockito to mock static methods).
If you wanna do like I did, I recommend you to test the correctness of specifications with integration tests, and for the rest, just if the right method was called.
For example:
public class CdrSpecs {
public Specification<Cdr> calledBetween(LocalDateTime start, LocalDateTime end) {
return (root, query, cb) -> cb.between(root.get(Cdr_.callDate), start, end);
}
}
Then you have an integration test for this method, which will test whether the method is right or not:
#RunWith(SpringRunner.class)
#DataJpaTest
#Sql("/cdr-test-data.sql")
public class CdrIntegrationTest {
#Autowired
private CdrRepository cdrRepository;
private CdrSpecs specs = new CdrSpecs();
#Test
public void findByPeriod() throws Exception {
LocalDateTime today = LocalDateTime.now();
LocalDateTime firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
List<Cdr> cdrList = cdrRepository.findAll(specs.calledBetween(firstDayOfMonth, lastDayOfMonth));
assertThat(cdrList).isNotEmpty().hasSize(2);
}
And now when you wanna unit test other components, you can test like this, for example:
#RunWith(JUnit4.class)
public class CdrSearchServiceTest {
#Mock
private CdrSpecs specs;
#Mock
private CdrRepository repo;
private CdrSearchService searchService;
#Before
public void setUp() throws Exception {
initMocks(this);
searchService = new CdrSearchService(repo, specs);
}
#Test
public void testSearch() throws Exception {
// some code here that interact with searchService
verify(specs).calledBetween(any(LocalDateTime.class), any(LocalDateTime.class));
// and you can verify any other method of specs that should have been called
}
And of course, inside the Service you can still use the where and and static methods of Specifications class.
I hope this can help you.
If you are writing Unit Tests then you should probably mock the call to findAll() method of articleRepository Class using a mocking framework like Mockito or PowerMock.
There is a method verify() using which you can check if the mock is invoked for the particular parameters.
For Example, if you are mocking the findAll() method of articleRepository Class and want to know if this method is called with particular arguments then you can do something like:
Mokito.verify(mymock, Mockito.times(1)).findAll(/* Provide Arguments */);
This will fail the test if mock has not been called for the arguments that you provided.
Your problem is that you are doing too many things within that one method. You should have three different methods that work on articleRepository.
Then you can use mocking as the others suggest:
setup your mocks so that you know which call on articleRepository should be made
verify that exactly the expected calls are happening
Please note: these three methods should be internal; the main point there is: you can't test this method with ONE call from the outside; as it is doing more than one thing, depending on the input that you provide. Thus you need to create at least one test method for each of the potential paths in your code. And that becomes easier (from a conceptual point of view) when you separate your code into different methods.
Hello I would like to know what is the best approach to mock void methods for example: I have a PersonManager under the test and then I have dao that is mocked.
class PersonManager {
PersonDao dao...
PersonManager(PersonDao dao)...
Preson find(String person)...
void delete(String person)...
}
class PersonManagerTest {
Map<String, Person> persons ..... = "person1", "person2", "person3";
PersonDao mock...
PersonManager manager = new PersonManager(mock);
//easy one
#Test public void shouldReturnExistingPerson() {
expect(mock.find("person1").andReturn(persons.get(0));
Person result = manager.find("person1");
// replay and verify logic
}
//but what should I do here?
#Test public void shouldDeleteExistingPerson() {
//should I remove a person from testing Map holding test data? or what am I doing wrong
}
}
So testing method with return was easy but how to toset void method? Thank you for suggestions, and Mcokito examples are welcomed too.
}
With easy mock, you don't need to wrap void functions around expect(). You just need to do something like:
obj = createMock(...)
obj.someVoidMethod();
replay(obj);
...
verify(obj);
It depends entirely on what you're trying to test.
In mockito, if you want to check only that the DAO delete method is called with the correct parameter, then verify is what you want.
I would suggest that this is exactly what you want since your unit test for PersonManager should not be testing PersonDao.
When deleting something, I suggest returning the object you just deleted. It makes testing much, much easier and allows doing things after you deleted (e.g. showing notice, logging, etc). I think most (all?) Java collections are doing so.
Mockito provides a static verify method that can verify when you call any method, even those that have void as return type. For your code sample, the following mockito code should work:
// Put this among your import statements
import static org.mockito.Mockito.*
class PersonManagerTest {
private PersonManager manager; // SUT
private Map<String, Person> mockedPersons;
private PersonDao mockDao;
// Don't forget to setup from scratch for each test
#Before public void setup() {
mockDao = mock(PersonDao.class); // mockito mock method
mockedPersons = new HashMap<String, Person>();
for (int i=1; i<=3; i++) {
mockedPersons.put("person"+i, mock(Person.class));
}
manager = new PersonManager(mockDao);
}
// setup dao to return a mocked person
private void whenPersonIsAdded(int i) {
Person personToReturn = mockedPersons.get("person"+i);
when(mockDao.find("person"+i)).thenReturn(personToReturn);
}
#Test public void shouldReturnExistingPerson() {
whenPersonIsAdded(1);
Person expectedPerson = mockPerson;
Person actualPerson = manager.find("person1");
assertEquals(expectedPerson, actualPerson);
}
#Test public void shouldDeleteExistingPerson() {
String expectedPersonString = "person1";
manager.delete(expectedPersonString);
verify(mockDao).delete(expectedPersonString);
}
}
Hope this helps.