I' ve got some business logic class:
public class SomeService {
public void doFirst() {}
public void doSecond() {
doFirst();
}
}
and test for it:
public class SomeServiceTest {
private SomeService service;
#Before
public void setUp() {
service = new SomeService();
}
#Test
public void doSecond_someCondition_shouldCallFirst() {
// given
...
// when
service.doSecond();
//then
how to verify doFirst() was called?
}
}
How to verify doFirst() was called not on mock, but real service?
I wonder why you want to test, what method your method under tests invoke. Sounds pretty much like whitebox testing to me.
In my opinion, you want to verify the outcome of the invocation and not the way to get there, as this might easily change (i.e. when refactoring).
So if the outcome of doSecond() is the same as doFirst() you could write a test for doFirst() and use the same test (i.e. set of assertions) for testing doSecond().
But if you really want to test, whether doFirst() has been invoked by doSecond() you could wrap your service in a spy and then call the verification on the spy:
//given
SomeService service = new SomeService();
SomeService spy = Mockito.spy(service);
//when
spy.doSecond();
//then
verify(spy).doFirst();
It sounds like you want to avoid the real doFirst being called in your test? if so, try this...
//given
boolean firstCalled = false;
SomeService fakeService = new SomeService {
#Override
public void doFirst() {
firstCalled = true;
}
}
//when
fakeService.doSecond();
// then
assertTrue(firstCalled);
This testing/mocking technique is called 'subclass and override' for obvious reasons.
Related
I want to create an integration test where a put method is called on a controller and it updates a certain object. During this process, a service class is involved which calls a third party API to do some stuff. In my case, I want to stub the service method which is involved in calling the third party as it is not the point to test the third party.
Having that said, I will present my code and I wait for an answer about why this does not work as expected and/or any other workaround.
This is my service class in which is the method call I want to stub.
public class ProjectService implements SomeInterfance {
// the third party service
private final DamConnector damConnector;
// some other fields
public ProjectDTO save(ProjectDTO projectDTO) {
log.debug("Request to save Project : {}", projectDTO);
// some operations
synchronizeWithDamAndSave(project, parentChanging); //this is the method call I want to be skiped
//other operations
return projectMapper.toDto(project, this);
}
//the method that I want to stub
public Asset synchronizeWithDamAndSave(Project project, boolean includeDocuments) {
Asset asset = synchronizeWithDam(project, includeDocuments);
projectRepository.save(project);
return asset;
}
}
And my integration test class:
#SpringBootTest(classes = SppApp.class)
public class ProjectResourceIT {
//other fields
//my service use autowire as it needs to make the service calls
#Autowired
private ProjectService projectService;
//this is my setup method where I create the spy of project service and define the doReturn behavior when my method is called
#BeforeEach
public void setup() {
ProjectService spyProjectService = Mockito.spy(projectService);
Mockito.doReturn(new Asset()).when(spyProjectService).synchronizeWithDamAndSave(Mockito.any(Project.class),Mockito.anyBoolean());
MockitoAnnotations.initMocks(this);
final ProjectResource projectResource = new ProjectResource(spyProjectService, clientService, securityService);
this.restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource)
.setCustomArgumentResolvers(pageableArgumentResolver)
.setControllerAdvice(exceptionTranslator)
.setConversionService(createFormattingConversionService())
.setMessageConverters(jacksonMessageConverter)
.setValidator(validator).build();
}
}
...
public void updateProject() throws Exception {
// initialization of the test
// this is where I call my controller
restProjectMockMvc.perform(put("/api/projects")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(projectDTO)))
.andExpect(status().isOk());
}
}
The problem in my case is that mockito enters in synchronizeWithDamAndSave method just after
Mockito.doReturn(new Asset()).when(spyProjectService).synchronizeWithDamAndSave(Mockito.any(Project.class),Mockito.anyBoolean());
this line is called, before the method to be called from the rest api.
What should I do? Any hints about why this is happening?
Spring Boot's proxies are not working wit Mockito. Use #SpyBean instead of #Autowired.
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));
}
I have a class called Availability.java and have two methods.
public Long getStockLevelStage() {
//some logic
getStockLevelLimit();
}
public Long getStockLevelLimit() {
String primaryOnlineArea = classificationFeatureHelper.getFirstFeatureName(productModel, FEATURE_CODE_PRODUCT_ONLINE_AREA_PRIMARY, language);
................
return new Long();
}
I'm writing a unit test class AvailabilityTest.java.
#RunWith(MockitoJUnitRunner.class)
public class AvailabilityTest {
#InjectMocks
private Availability availability = new Availability();
#Test
public void testGetStockLevelStage() {
availability.getStockLevelStage();
}
}
When I call availability.getStockLevelStage() method, it calls getStockLevelLimit() method. Is it possible to mock the internal method call?
In this case, I don't want getStockLevelLimit() to be executed, when getStockLevelStage() gets executes.
Please help.
Try this:
#RunWith(MockitoJUnitRunner.class)
public class AvailabilityTest {
#InjectMocks
#Spy
private Availability availability = new Availability();
#Test
public void testGetStockLevelStage() {
Mockito.doReturn(expectedLong).when(availability).getStockLevelLimit();
availability.getStockLevelStage();
}
}
Here is an article I wrote on Mockito Spying if you need a further read.
if getStockLevelLimit() has not to be executed during your test, it means in a some way you want to mock the class under test.
Doing it reduces the relevance and the authenticity of the behavior tested.
You should mock dependencies and not internal methods of the tested class.
I suppose you don't want to execute getStockLevelLimit() because it uses external dependency that you want to isolate or something of similar.
So you should mock and isolate which is behind getStockLevelLimit() and that doesn't make directly part of the Availability class.
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.
Here is my code:
`public class Service {
callSomeService(ContextTpye1 c1,Parameter p){
//do something here
ContextTpye2 c2 = constructContext(c1,p);
if(c2.timeout()){
c2.audit();
}
}
}`
In the unit test, the Service, Parameter and ContextTpye1 are initialized. Is it possible to only mock c2.audit()? I wanna it to doNothing here. Thanks.
So the way I would attack the problem assuming constructContext(c1,p) is public is to when testing the Service class is to spy on the Service allowing you to mock the constructContext(c1,p) and returning a mock of ContextType2.
public class ServiceTest
{
private Service service = Mockito.spy(new Service());
private ContextType2 c2 = Mockito.mock(ContextType2.class);
#Test
public void testCallSomeService()
{
Mockito.when(service.constructContext(Mockito.eq(ContextType1.class), Mockito.eq(Parameter.class))).thenReturn(c2);
Mockito.when(c2.timeout()).thenReturn(true);
Mockito.when(c2.audit()).doNothing();
service.callSomeService(new ContextType1(), new Parameter());
}
}