I am working on the project where I want to have decent test-infrastructure.
I am using spring boot, which makes easier for testing separate layers of the project: for example
If I want to test controller layer I will mock (with mockito) service dependencies of the controller, and check whether right service method will be called on given http request, and expected http status will be returned. If I want to test service layer I will mock repository and business logic dependencies. And so on.
In my project, I am using spring validators to check whether request body is passed correctly (with the use of #InitBinder method I am adding my custom validators to the WebDataBinder, and with use of #Valid annotation, those validators are called on the parsed request body).
So my question is: is it good practice to mock validators and test only controller logic (validators will be tested in context of validator layer)?
I am just not sure which is the best practice, and is it normal to test validators along with controllers?
Mocking is not always best option, when you are testing your controller logic, validation logic and especially business logic. I would not recommend to mock any of these.
You can use various framework to test:
Controller logic - RestAssured or MockMvc
Business logic - Plain JUnit tests under SpringBootTest and SpringRunner
Validation logic - Plain JUnit tests under SpringBootTest and
SpringRunner
For further reading:
RestAssured: http://rest-assured.io/
Spring validator test: Writing JUnit tests for Spring Validator implementation
Related
I use Spring Boot with Kotlin and my project is splitted on modules where I have application layer with REST controllers and facades, domain layer with services and business logic and infrastructures layer for communication with external services or DBs. I think (but I can be wrong) that the best place for basic validation like notNull, notEmpty, max and min, size etc. is facade because both REST controllers and another modules communicate with it, but the problem is that javax validation annotation like #Valid are working only on REST Controller layer (in classes with annotation #RestController) and when I try to create some tests for this facade then fields with wrong values return NullPointerException instead of MethodArgumentNotValidException. I tried to create WebMvcTest but also returns wrong exception. Is it some solution for it? I saw that I could call some validator inside the method but it looks like much more complex approach than annotation on method's argument.
You can inject the javax.validation.Validator into any Spring component. For example, into a facade component, and perform validation in the facade layer:
#Autowired
Validator validator;
Set<ConstraintViolation<UserRequestDTO>> violations = validator.validate(userRequest);
This way you can remove the #Valid annotation from controllers at all. And this approach puts validation results under the your control.
I have the following configuration
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootApplication(scanBasePackageClasses= {})
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes= {})
#ActiveProfiles("local")
I want to run a JUnit test without mocking the MongoRepository calls but it automatically mocks the MongoRepo calls and gives back null. Is their a way around it?
Firstly, you should decide what kind of test you want to perform,
Unit test
or
Integration test
If you are doing unit test , you should write separate test cases for each layer
Controller layer - use mockmvc and mock service layer calls
Service layer - Here you have two options, YOu can mock repository calls or you can use some in memory database(like Fongo) and put some data before testing and test it.
If you want to test all layers together and with real database then you should write Integration tests.
Simple scenario:-
In a Spring 4 app the following #Valid gets triggered when I make a REST call but not when I make an API call. The docs talks about it but does not state how to do it the way I want.
#RequestMapping(name="/something")
public Entity save(#Valid Entity e){ return repo.save(e);}
Without writing any custom AOP code to achieve this myself etc. how do I get bean validation #Valid triggered in Spring ? Looking for any Spring or Hibernate configuration that will turn this on for simple API calls.
Example: When I bundle my component as a maven I would like to get my beans validated irrespective of whether they run in a web context or outside , say Spring Batch or just JUnit Tests.
And when I bundle this jar in a web app I definitely don't want this executed twice.
I am developing a web application using Spring + Hibernate, plus CXF to convert my Service layer into a WebServices endpoint. I want to unit test my code, and when it comes to the DAOs I have no trouble: I create an in-memory database filled with my test data, then test DAOs against that.
But when testing the Service layer, most of my methods are like these:
#Override
#Transactional
public void saveProgramacion(ProgramacionDTO programacion) {
programacionDAO.persist(this.map(programacion, Programacion.class));
}
That is, my method just maps the VO to a DTO (using an external mapper) then calls a method of my DAO. Just that.
I used mockito to mock my DAO but honestly there are no instructions to provide mockito with since the service method itself does very little and does not check the DAO result. Given the fact that the mapper is an external dependency and thus would require its own unit test, what should I be testing here? What would be a proper unit test in this case?
I am writing test case for my webflow using org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests
public class MyFlowExecutionTests extends AbstractXmlFlowExecutionTests {
}
In some cases my logic is simple, So I invoke my service layer directly from the Spring webflow.
In some cases I use an extenstion of org.springframework.webflow.action.MultiAction classes and I invoke my service layer from the action classes.
In the first scenario, wrting test case is straight forward. In the second scenario, I found it really complex to write the test cases using org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests for the Action class.
In the first scenario, I can mock all the service classes used from my flow. In the second scenario, using easy mock class extension, I can mock the action class. But then I need to mock the service layers used inside, which I think mock can't handle that well.
I am now thinking of somehow moving the Action class code to Spring EL. Or Anybody have a better idea for testing the action class code along with webflow code?