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.
Related
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 have foolowing class which I would like to mock:
BusineesLayer:
/**
* Created by Alexandr on 14.05.2016.
*/
public class BusineesLayer {
public OrderModel orderModel;
public DbService dbService;
...
public BusineesLayer(OrderModel orderModel,DbService dbService) {
this.orderModel = orderModel;
dbService = dbService;
}
public BusineesLayer() {
}
public boolean checkItemsInDb(List<Items> items) throws HandleOrderExeption {
...
return result
}
public boolean handleOrder() throws HandleOrderExeption {
checkItemsInDb(orderModel.getItemsList());
boolean res =dbService.addOrder(orderModel.getItemsList(),
orderModel.getCustumerName(),
countTotalSum(orderModel.getItemsList())
);
return res;
}
}
I would like to test hanldeOrder() method and in order to make it less excess insted of checkItemsinDb() inside invoke "true";
So, my test looks like this:
#Test
public void handleorderTest() {
...
BusineesLayer layer = Mockito.mock(BusineesLayer.class);
layer.dbService = busineesLayer.dbService;
layer.orderModel = busineesLayer.orderModel;
Mockito.when(layer.checkItemsInDb()).thenReturn(true);
boolean res = layer.handleOrder();
assertThat(res, equalTo(true));
}
but it always return false and doesn't go through handlOrder() at all
Is any ways to solve it? Or how can I refactor my code to test it?
You do not test mocks, you use mocks to help you test.
I think you've just become confused at how you are using mocks. Mocks allow us to simulate and can responses to objects we are testing. If you're testing the handleOrder method, then you should mock anything that interacts with that method, in this case DbService and OrderModel.
#Test
public void handleorderTest() {
BusineesLayer layer = new BusineesLayer(); //we are testing this!
DbService dbService = Mockito.mock(DbService.class);
OrderModel orderModel = Mockito.mock(OrderModel.class);
layer.dbService = dbService;
layer.orderModel = orderModel;
Mockito.when(orderModel.getItemsList()).thenReturn(new ArrayList<Items>());
Mockito.when(dbService.foo()).thenReturn(true);
//mock up multiple calls so your service will provide true
boolean res = layer.handleOrder();
assertThat(res, equalTo(true));
//repeat for false, and so on
}
If, however, you are trying to test the dbService call, then you should create a test for it without the business layer at all. The business layer doesn't depend on anything except calls to other methods, so whether you use those real objects or mocked versions of those objects, the functionality should be the same. The business logic only appears to fail if DBService or OrderModel break, so you would test service and model separately (without involving the business layer) to test those.
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.
I've been trying to do a unit test of my DAO but I haven't find out the way to do it yet and I'm feeling a little desperate. I have a tiny DAO that looks like this:
public interface ElectionsDao {
List<String> getDates();
}
I'm using Spring framework to do DI using SimpleJdbcTemplate. My implementation looks like this:
public class ElectionsDaoImpl extends SimpleJdbcDaoSupport implements ElectionsDao {
public List<String> getDates() {
List<String> dates = new ArrayList<String>();
try {
dates = getSimpleJdbcTemplate().query("SELECT electiondate FROM electiondate", new StringRowMapper());
} catch (DataAccessException ex){
throw new RuntimeException(ex);
}
return dates;
}
protected static final class StringRowMapper implements ParameterizedRowMapper<String> {
public String mapRow(ResultSet rs, int line) throws SQLException {
String string = new String(rs.getString("electiondate"));
return string;
}
}
}
What I want to do is just a unit test of getDates() using EasyMock but I haven't found the way to do it. I'm so confused. Can anybody help me please?
It looks as though getSimpleJdbcTemplate is the biggest problem for unit testing. One way you could test is to extend the class under test and override the getSimpleJdbcTemplate method e.g.
public class ElectionDaoTest {
/** Class under test */
private ElectionsDaoImpl dao;
#Before
public void setUp() {
dao = new ElectionsDaoImpl(){
SimpleJdbcTemplate getSimpleJdbcTemplate(){
// Return easy mock version here.
}
};
}
#Test
// Do tests
}
There may be an easier way with EasyMock, but I'm not that familiar with it.
Thank you for your comments. I decided to do the test using Spring. My test code ended like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="classpath:beans.xml")
public class DBConectionTest{
#Resource
private ElectionsDao electionsDao;
#Test
public void testGetDates(){
List<String> dates = electionsDao.getDates();
assertNotNull(dates);
}
}
I'm using the same xml file that I use when running my project. Hope it helps someone.