I have this service that I need to create Unit test for:
SomeObject obj = new SomeObject();
String objConfig = "<root id=%id% param1="something">....</root>"
obj.setField1("value1");
obj.setField2("value2");
someObjectDao.create(obj);
Long objId = obj.getId();
obj.setConfig(objConfig.replace("%id%", objId.toString()));
someObjectDao.update(obj);
Now, the problem is that in a real case, the DAO create will assign ID on the object, but how do I set the object ID through a Unit test?
You can do this in two ways (if you are using JUnit 4):
Use real DAO and mark test class as #Transactional and #Rollback. Every test method will be opened in separate transaction, record will be inserted into database and processed as in real system, but after method exit rollback will occure.
Use some mocking framework, i.e. mockito, mock create() method of someObjectDao, setting id as you want.
Related
I'm using spring framework and testing with Junit and mockito.
Right now I have a method in my service which is using a few objects I create in the test, let's call them configObject1 and configObject2, I send them to the method as a parameter, and then the method start making some calls to another repositories along those configuration objects, those repositories are mocked and work well, the method makes a List of "CalculusResult" from those queries/configObjects. After that I use a repository extending CRUDRepository and make a saveAll(). Then it should return an iterable with the entities, but for some reason after the saveAll method it returns an empty list.
Test:
#Test
...
configObject1 conf1 = new configObject1 (...);
configObject2 conf2 = new configObject2 (...);
Calculusresult calcRes = new CalculusResult(null,...,new java.sql.Date(system.currentTimeMilis()),...);
List<CalculusResult> resList= new ArrayList<CalculusResult>();
resList.add(calcRes);
Calculusresult calcRes2 = new CalculusResult(1,...,new java.sql.Date(system.currentTimeMilis()),...);
List<CalculusResult> resList2= new ArrayList<CalculusResult>();
resList2.add(calcRes2);
when(calculusResultRepository.saveAll(resList)).thenReturn(resList2);
...
assertTrue(!response.isEmpty())
Method from the service:
...//The method is building the list of calculusResults
resCalc.setDate(new java.sql.Date(system.currentTimeMilis()))
resList.add(calcres);//CalculusResult object is added to the list, this object is well made
List<CalculusResult> savedResults = (List<CalculusResult>) calculusResultRepository.saveAll(resList); //This returns an empty list (If I don't cast, it also returns nothing)
for(CalculusResult calcres : savedResults){
... //This makes nothing because savedResults is empty, making the response empty and failing the test.
Repository:
#Repository
public interface CalculusResultRepository extends CrudRepository<CalculusResult, Long> {
}
I'm not sure but I think the problem may be that the object I'm creating in the test is different to the one in the service because one of the attributes is an sql Date of the moment it's created, so maybe it's not triggering "when(calculusRepository.saveAll(reslist)..." in the test because the object created in the test and the one created in the service have different Dates in that atribute.
If that's the case, is there a way to fix it? Or is the problem a completely different thing?
You can use Mockito ArgumentMatchers to match any argument.
when(calculusResultRepository.saveAll(Mockito.any(List.class)))
.thenReturn(resList2);
I'm writing some Unit Tests for my Service class, specifically, an update method that does exactly that, update an Entity with the given data from a request.
The problem is, I'm using ModelMapper to map the request data to the entity and when the test goes through the mapping statement it doesn't actually call the modelMapper but the mock .... which does nothing because it's a mock.
How should I mock its behavior?
public EntityNode updateEntity(String code, EntityDTO request) {
String message = "Entity with code: %s not found";
EntityNode entity = repository.findByCode(code)
.orElseThrow(() -> new EntityNotFoundException(String.format(message, code)));
modelMapper.map(request, entity);
return repository.save(entity);
}
I've thought about using an ArgumentCaptor but I'm not really sure if it suits my needs or if it's really what I need to do what I want.
This is my unfinished test method. After writing all of this I think I should stub ModelMappers.map() somehow and also return the result of calling the ModelMapper stub map() method when calling repository.save(entity).
#Test
void givenValidEntity_whenUpdateEntity_shouldUpdateProperties() {
//given
String code = "TEST";
Entity expected = new Entity();
expected.setName("Old");
EntityDTO request = new EntityDTO();
request.setName("New")
given(repository.findByCode(code)).willReturn(expected);
//when
Entity updatedEntity = service.updateEntity(code, request);
//then
assertEquals(request.getName(), updatedEntity.getName());
}
Does this make any sense?
Thanks
What does the changing?
By looking at the current code it seems like the modelMapper does the changing. This would mean that changing unit test should be in modelMapper's own unit test.
What does the EntityNode updateEntity(String code, EntityDTO request) do?
It fetches an entity from a repository, takes your entity, passes it through modelMapper and saves the result via repository. So while testing this function you should test only that those things happen with correct arguments, not what the modelMapper itself does.
If you want to test your function + modelMapper then this is more of an integration test not a unit test.
Additional notes
Ideally modelMapper would not mutate anything. Instead it would take the two arguments and return the result as a new object. This way it would be more easily testable and mockable (you could avoid using argument verification while testing updateEntity function).
You could extract the mapping to another class that returns the mapped entity, so you could mock that returned value.
I am trying to build an integration test method in Java, but there are some service methods that have no returning value (void). So, in this scene, normally I would create a record and then retrieve this record using the id of created record. However, as there is no returned value, how can I write integration test for example such a kind of service method? Is that possible?
public void saveProperties(final Request request, final UUID productUuid) {
repository.saveProduct(request, productUuid);
}
You can actually verify the service method was called or not using Mockito.verify.
Sample usage:
Mockito.verify(mockedObject, Mockito.times(1)).saveProduct(any(Request.class), any(UUID.class));
This will validate that the saveProduct was called on your mocked object.
Consider the scenario where I am mocking certain service and its method.
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");
//assert
assertEquals("Jim", emp.getName(1));
assertEquals("Mark", emp.getName(2));
In the above code when emp.getName(1) is called then mock will return Jim and when emp.getName(2) is called mock will return Mark. My Question is I am declaring the behavior of Mock and checking it assertEquals what is the point in having above(or same kind of) assert statements? These are obviously going to pass. it is simply like checking 3==(1+2) what is the point? When will these tests fail (apart from changing the return type and param type)?
As you noted, these kind of tests are pointless (unless you're writing a unit test for Mockito itself, of course :-)).
The point of mocking is to eliminate external dependencies so you can unit-test your code without depending on other classes' code. For example, let's assume you have a class that uses the Employee class you described:
public class EmployeeExaminer {
public boolean isJim(Employee e, int i) {
return "Jim".equals(e.getName(i));
}
}
And you'd like to write a unit test for it. Of course, you could use the actual Employee class, but then your test won't be a unit-test any more - it would depend on Employee's implementation. Here's where mocking comes in handy - it allows you to replace Employee with a predictable behavior so you could write a stable unit test:
// The object under test
EmployeeExaminer ee = new EmployeeExaminer();
// A mock Employee used for tests:
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");
// Assert EmployeeExaminer's behavior:
assertTrue(ee.isJim(emp, 1));
assertFalse(ee.isJim(emp, 2));
In your case you are testing a getter, I don't know why you are testing it and no clue why would you need to mock it. From the code you are providing this is useless.
There is many scenarios where mocking make sense when you write unit-test you have to be pragmatic, you should test behaviors and mock dependencies.
Here you aren't testing behavior and you are mocking the class under test.
There is no point in that test.
Mocks are only useful for injecting dependencies into classes and testing that a particular behaviour interacts with that dependency correctly, or for allowing you to test some behaviour that requires an interface you don't care about in the test you are writing.
Mocking the class under test means you aren't even really testing that class.
If the emp variable was being injected into another class and then that class was being tested, then I could see some kind of point to it.
Above testcase is trying to test a POJO.
Actually, You can ignore to test POJO's, or in other words, they are automatically tested when testing other basic functionalities. (there are also utilities as mean-beans to test POJO's)
Goal of unit-testing is to test the functionality without connecting to any external systems. If you are connecting to any external system, that is considered integration testing.
Mocking an object helps in creating mock objects that cannot be created during unit-testing, and testing behavior/logic based on what the mocked object (or real object when connecting to external system) data is returned.
Mocks are structures that simulate behaviour of external dependencies that you don't/can't have or which can't operate properly in the context of your test, because they depend on other external systems themselves (e.g. a connection to a server). Therefore a test like you've described is indeed not very helpful, because you basically try to verify the simulated behaviour of your mocks and nothing else.
A better example would be a class EmployeeValidator that depends on another system EmployeeService, which sends a request to an external server. The server might not be available in the current context of your test, so you need to mock the service that makes the request and simulate the behaviour of that.
class EmployeeValidator {
private final EmployeeService service;
public EmployeeValidator(EmployeeService service) {
this.service = service;
}
public List<Employee> employeesWithMaxSalary(int maxSalary) {
List<Employee> allEmployees = service.getAll(); // Possible call to external system via HTTP or so.
List<Employee> filtered = new LinkedList<>();
for(Employee e : allEmployees) {
if(e.getSalary() <= maxSalary) {
filtered.add(e);
}
}
return filtered;
}
}
Then you can write a test which mocks the EmployeeService and simulates the call to the external system. Afterwards, you can verify that everything went as planned.
#Test
public void shouldContainAllEmployeesWithSalaryFiveThousand() {
// Given - Define behaviour
EmployeeService mockService = mock(EmployeeService.class);
when(mockService.getAll()).thenReturn(createEmployeeList());
// When - Operate the system under test
// Inject the mock
EmployeeValidator ev = new EmployeeValidator(mockService);
// System calls EmployeeService#getAll() internally but this is mocked away here
List<Employee> filtered = ev.employeesWithMaxSalary(5000);
// Then - Check correct results
assertThat(filtered.size(), is(3)); // There are only 3 employees with Salary <= 5000
verify(mockService, times(1)).getAll(); // The service method was called exactly one time.
}
private List<Employee> createEmployeeList() {
// Create some dummy Employees
}
I am looking for information to build unit test for typical DAO methods (find user by username, etc.) and I found several examples using mocks like this one: http://www.christophbrill.de/de_DE/unit-testing-with-junit-and-mockito/
#Test
public void testComeGetSome() {
// Mock the EntityManager to return our dummy element
Some dummy = new Some();
EntityManager em = Mockito.mock(EntityManager.class);
Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy);
// Mock the SomeDao to use our EntityManager
SomeDao someDao = Mockito.mock(SomeDao.class);
Mockito.when(someDao.comeGetSome(1234)).thenCallRealMethod();
Mockito.when(someDao.getEntityManager()).thenReturn(em);
// Perform the actual test
Assert.assertSame(dummy, someDao.comeGetSome(1234));
Assert.assertNull(someDao.comeGetSome(4321));
}
There is also a similar one in Lasse Koskela's book using EasyMock instead of Mockito.
The thing is: what are we really testing in these examples? We are basically telling through mocks what object the query should return, and then asserting that in fact it returned the object we told it to return.
We are not testing if the query is correct or if it returns a different object or no objects at all (or even more than one object). We cannot test if it returns null when the object does not exist in the database. This line
Assert.assertNull(someDao.comeGetSome(4321));
works because there is no scripted interaction for that argument, not because the object does not exist.
It looks like we are just testing if the method calls the proper methods and objects (em.find).
What is the point of unit testing this? Are there any good frameworks in Java to quickly set up an in memory database and perform tests with it?
Your doubts really make sense. Actually there is no need to test DAO with unit tests in most cases because unit tests deal with one layer, but DAO cooperate with database layer.
This article explains this idea:
http://www.petrikainulainen.net/programming/testing/writing-tests-for-data-access-code-unit-tests-are-waste/
Hence we should test DAO and database layer with integration tests.
Integration tests take into account both DAO and database layer.
This article will provide your with Spring + Hibernate example:
https://dzone.com/articles/easy-integration-testing
It looks loke more like service tests, than a real DAO tests.
For example, I'm using dbunit to test my DAO layer.
For example, I have Author table with 2 fields: id and name.
I'm creating a dataset xml file like
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<AUTHOR AUTHOR_ID="1" NAME="FirstAuthor"/>
...
<AUTHOR AUTHOR_ID="10" NAME="TenthAuthor"/>
</dataset>
And then in my test class using Mockito I'm testing my DAO methods like
#Test
#DatabaseSetup(value = "/dao/author/author-data.xml")
public void testFindAll() {
List<Author> authorList = this.authorDAO.findAll();
assertEquals(10, authorList.size());
}