So I have the bellow method which I want to perform a unit test on.
public List<Project> getProjects(Task task) {
Criteria<Project> criteria = this.myRepository.getCriteria(Project.class);
criteria.add(Comparison.eq("order", task.getOrder()));
criteria.addOrder(Order.asc("projectNumber"));
return this.myRepository.findList(Project.class, criteria);
}
So it actually gets the task object(It is a JPA model object) and goes throw the project table and finds all the projects which have this project's orders. Order is common in both tables.
Anyways, query itself is not that imp. It queries db and returns some data. Now my problem how can I perform a unit test on this with easymock?
#Test
public void testGetProjects() throws Exception {
myRepository = new CreateMyRepositoryWrapper(); --> This is a class which just returns the entityManger. but here we can consider this as a pojo.
Task task = EasyMock.createNiceMock(Task.class);
Order bom = EasyMock.createNiceMock(Order.class);
Project project= EasyMock.createNiceMock(Project.class);
project.setProjectName("project"); ------> Can I call a seeter on a mocked object?
project.setProjectNumber("1");
EasyMock.replay(project);
List projects= new ArrayList(Arrays.asList(project));
bom.setProjects(projects); ------------> Does it make sense to do this?
EasyMock.expect(task.getOrders()).andReturn(bom);
TestClass instance = new TestClass();
instance.setMyRepository(myRepository);
EasyMock.replay(task,bom);
instance.getProjects(task);
}
So this passes the test case. But I am not sure with all those mocking what I am actually testing.. Because it just shows that those methods are being called. But since they are mocked I am not sure if I can use assertEquals or not and even if I can I am getting an exception cuz I have to add more to the above code I think.
So my question: For the method mentioned what should be the proper unit test case?
Thanks.
I think you have this mocking backwards. Mock myRepostory, then set up the myRepository mock to return a Criteria object and to return a project list when that Criteria object is passed to findList.
Task, Order and Project can probably just be instantiated.
Now, instance.getProjects(task) will return something. You can check to make sure that thing that got returned is the same thing you said should be returned from findList. Now you've actually tested something, albeit nothing particularly interesting.
You probably want to validate that the criteria object was set up correctly before it was passed to findList. To do that, you either have to make criteria a mock, then you can set up your expectations for what methods are called. The tricky part here is that Hibernate Restriction classes do not have a non-default equals implementation, so you have to write your own matcher to check that the Restrictions being passed to the criteria are the same (functionally) as the Restrictions you expect.
Another possibility is to set up criteria as an actual Criteria object. (You still set up your myRepository mock to return it.) Then, after the function is called, you can check the contents with some substring matching on the toString() method or any other ways you know to inspect the Criteria object.
A final (unit test) possibility is to not use a mocking framework for the Criteria object, but some hand-coded one that you write that allows you to inspect all of the Restrictions that were added to it.
All of this makes a good case for this method actually being tested with integration testing instead. You wind up doing a lot of work to verify some not very interesting things and your tests can become quite brittle if you try to refactor the code. (I've done it myself, so I speak from experience.)
Related
public class A {
public List<Model> getModels() {
List<Model> models = (some logic to find all models...)
models.forEach(model -> doSharedLogic(model));
}
public Model getModel(int id) {
Model model = (some logic to find Model by Id...)
doSharedLogic(model);
}
private void doSharedLogic(Model model) {
// manipulations with model...
}
}
Let's say I have the code above. I want to unit test public API (getModels and getModel methods). They use shared logic extracted into separate method doSharedLogic().
Question: How to correctly test those two methods if basically logic is completely the same?
**My assumptions: **
test getModel method with testing of all possible results for doSharedLogic();
do same for getModels();
But it's going to cause duplication of code in tests.
If I just test doSharedLogic as part of one of those public methods(for example: getModel()), I can't be sure that somebody won't come later, change something and break code in second method(getModels()) by removing shared logic for example
My assumptions: test getModel method with testing of all possible results for doSharedLogic();do same for getModels();
I would test each method for what they do and avoid duplication.
You have getModel() which gets a single instance. Test it for cases related to getting one instance including edge cases such as not found. If this code is also doing data transformation, then here is where I would test that the data is correct after the transformation, probably using a mock to inject data.
You have getModels() which gets multiples - all of them probably if it doesn't take some query string. Test it for cases that return multiple models, including the single or empty case. As this code is just calling getModel() under the covers, you should not reproduce any transformation logic tests and focus on testing the additional logic of "get many".
If you are really worried about someone changing the lgoic of getModels() later to not call getModel(), I would put that in comments in getModel() so that future editors know that if they remove that dependency they may need to add additional tests.
I would definitely not add a bunch of duplicative data transformation tests in both.
I've problems with test methods which only get data from entity and assign it to DTO.
I passed empty DTO, and entity created by entityMother. The method works correctly, but I don't know how to make assertion for this. I think that creating assertion for each value/property of this DTO is not a right way to test it.
Why I need to test methods like this?
The methods that set data from entity to DTO has small formatting specyfic fields. Like splitting a string etc.
#Test
public void shouldSetAvailabilities() {
EditedTemplateShowDto editedTemplateDto = new EditedTemplateShowDto();
productTemplateEditService.getAndSetAvailabilities(editedTemplateDto, editedProduct);
//Here should be condition which check that the metod set data
}
I just need to check that the method didn't throw any errors, and none of fields has assigned null value.
The possible solutions are:
You may serialize your objects to JSON then compare the resulting strings. (Cleanest way)
Overriding a matching toString() then compare the resulting strings.
Put several assert condition using reflection (to check the variable name) in a test to check there are no any null value or not mapped value (Bad Practice).
Why I need to test methods like this?
First of all, you don't need to test anything. If you feel the code is extremely straight forward then I would advice to just invest your time into something else. Or perhaps write one sweeping test so at least you have code coverage (but IMO you'd be doing this more for the stats than actual quality of your product).
I just need to check that the method didn't throw any errors
That's easy! Just write a unit test that calls the method. If the method throws any exceptions, the test will fail. If you want to make your test method more intent-revealing, you could explicitly write it like:
try {
productTemplateEditService.getAndSetAvailabilities(editedTemplateDto, editedProduct);
} catch(Exception e) {
fail("Should not have thrown any exception");
}
But again, I'd only do this with methods I expect to throw exceptions (e.g. because they have exception paths or use other code/libraries that may throw exceptions). The default behavior of any unit test is to fail when it encounters an uncaught exception.
none of fields has assigned null value.
The JUnit way is to use assertNotNull in your test method on any fields you want to ensure are not null.
If you want a more generic approach there are additional libraries like assertj's hasNoNullFieldsOrProperties.
assertThat(editedTemplateDto).hasNoNullFieldsOrProperties();
Or you could write your own code using reflection like:
for (Field f : editedTemplateDto.getClass().getDeclaredFields())
assertNotNull(f.get(editedTemplateDto))
But I'd advice against this as it makes your test code harder to understand (and possibly brittle because reflection itself can be tricky)
The methods that set data from entity to DTO has small formatting
specyfic fields. Like splitting a string etc.
This makes a unit test meaningful: verify if the fields in the DTO are filled as expected. So don't just test on notNull but test on
Assert.assertEquals("FieldX has a wrong value","myexpectedValue",dto.getFieldX());
This way you test if the split logic behaves as expected.
Also test it with null values in all optional fields to verify you don't get NullPointerException.
I have a builder that create a JPA Specification according to filters. How do I test the builder ? assertEquals method always return false when comparing Specifications...
I already try to call Specification::toPredicate method with mock args but the returned value is null. I would like to avoid loading the entityManager.
Specification<MyClass> nullSpecification = Specification.where(null);
Specification<MyClass> nullSpecification2 = Specification.where(null);
assertEquals(nullSpecification, nullSpecification2);
I expected assertEquals(nullSpecification, nullSpecification2) to return true but the actual value is false. How can I compare JPA Specification ?
I see the following options.
Bite the bullet and create an integration test, i.e. create an EntityManager and run queries against an in memory database or Testcontainers.
Inspect the internals of the generated Predicate by passing in carefully configured mocks and then using type checking, reflection and knowledge of internals of your JPA provider to assert that you'll get the right predicate.
The problem with the 2nd approach is that it is very brittle and is likely to break although the Specification is actually fine.
I therefore would go with option 1 although I'd prefer a unit test as well.
If I have to test a service that uses a mutable entity I would build the smallest object that I need (a real one) and pass it to my service. Example:
User joe = new User();
joe.setEmail("joe#example.com");
resetPasswordService.resetPassword(joe);
verif(emailServiceMock).sendEmail("joe#example.com", "Your password has been reset!");
Obviously User has lots of fields but I do not set them since resetPasswordService does not need them. This is very refactor-friendly since if I rename a User field that is not the email this test will not be changed.
The problem appears when I try to do the same with an Immutables object. I will stick with the same example and turn User from an entity into an immutable.
#Value.Immutable
public abstract class User {
public abstract String getEmail();
public abstract PostalAddress getPostalAddress();
//more fields
}
User joe = new ImmutableUserBuilder().email("joe#example.com").build();
resetPasswordService.resetPassword(joe);
verif(emailServiceMock).sendEmail("joe#example.com", "Your password has been reset!");
java.lang.IllegalStateException: Cannot build User, some of required attributes are not set [postalAddress, signupDate, city, ....]
This fails in the builder when it tries to build the object. So what should I do?
Use a mock for User and have it return mocks even if every time a mock returns a mock a fairy dies
Create a testing DSL and have some sort of factory to build the entire User tree structure with all the fields I don't need? Seems heavy and not so refactor-friendly. This makes the requirements of the test not so transparent.
Make all the fields in User #Nullable and have the builder not validate the object? This would expose me to the risk of having incomplete objects in production, right?
some other option I missed?
I know Users should be entities and not immutable value objects. I used User in this example since it is easy to understand.
Simple answer: you only use mocks if you have to.
Meaning: when you need to either control the behavior of an object in ways that the "real" class doesn't support. Or when you have to verify calls on the mock.
So: when you can write a test case that does what you want it to do without using mocking - then go for that.
Mock frameworks are tools. You don't use them because you can, but because they solve a problem for you that you otherwise can't address (easily).
Beyond that: as explained, the default should be to avoid mocks. On the other hand, programming is always about balancing efforts and "return on investment". That is why I used the word easily above. When it turns out that using a mock results in writing down 2, 3 easy-to-comprehend lines of code ... but using "the real" class is much more complicated (or relies on certain implicit assumption about how that class works) - then using a mock can be the better choice.
In that sense, the answer is: don't take answers and rules as golden standard. In the end, this is always about human judgement.
Your test is currently relying on implementation details of the password reset feature.
This is the behaviour you want to test:
Given a user
When that user requests a password reset
Then an email is sent
Suppose you decide later on to change the password reset feature so that the email includes their name:
Dear Joe,
You have requested a password reset...
Your test will now fail with a NullPointerException because you based your testing strategy on the assumption that the User instance will never need a name. A perfectly innocuous change has caused our test to fail when it should still pass.
The solution: use a real object. If you find your creating lots of users in different tests, refactor the user creation to its own function:
private User getUser()
{
User joe = new User();
joe.setEmail("joe#example.com");
joe.setName("Joe");
joe.setAge(20);
joe.setHeight(180);
return joe;
}
I have a public method to test which calls a private method. This private method in turn calls a db using a variable that's provided from the public method. While unit testing I provide a dummy variable data to the public method, but its breaking as no record can be pulled from database with that dummy variable. How do I handle this? Right now, we have a try catch block for that private method call and the test always fails. As long as it doesn't give an error, we are passing the test. Is that right approach?
I apologize if it doesn't make much sense, I am rather new to unit testing. Thanks.
You should mock the results from the database request. After all, a test should not be aware of the data in your DB.
Mockito can help you there.
Another solution would be to use an in-memory database like H2,and populate it before the test with the required data. You could use something like DBUnit to populate it.
These tests wouldn't be as unitary, but you could still use jUnit to do them.