Where should custom validation be placed in spring? - spring

Use case:
At springboot startup I want to validate some thing regarding annotations and application.properties file. So I want spring startup to fail if the rules
are violated.
What is the standard place to do this in Spring?
I have read this article: Baeldung - Article
Two solution that I like:
CommandLineRunner/ApplicationRunner
Registering an ApplicationListener
Are these OK for validating purpose as entry point?

You can create one validator bean and put all different validation logics in different methods and annotate them by #PostConstruct

Unless your configuration is changing frequently,
and it seems likely that it should not change frequently,
you only need to perform this type of validation in an integration test.
Just write a jUnit test that loads the configuration then performs the validation.
These are often, wrongly, called unit tests (because they use jUnit) but are actually integration tests.

Related

Should repositories in Spring Boot applications be tested directly?

Not sure if this will be considered a "legitimate question" or "purely opinion based", but is there a "best practice" with regards to directly testing a repository in a Spring Boot application? Or, should any integration testing simply target the associated service?
The reasoning for the question is simply the fact that, for the most part, a repository in a Spring Boot application contains no project-generated code. At best, it contains project-defined method signatures which Spring generates implementations for (assuming correct naming conventions).
Thanks...
If you can mess it up, you should test it. Here the opportunities to mess up can include:
Custom Queries (using #Query) might be wrong (there can be all kinds of logic mistakes or typos writing a query with no compile-time checking)
Repository methods where the query is derived from the method name might not be what you intended.
Arguments passed in, the type on the parameter list might not match the type needed in the query (nothing enforces this at compile time).
In all these cases you're not testing Spring Data JPA, you're testing the functionality you are implementing using Spring Data JPA.
Cases of using provided methods out of the box, like findOne, findAll, save, etc., where your fingerprints are not on it, don't need testing.
It's easy to test this stuff, and better to find the bugs earlier than later.
Yes, I think is a good pratice to do that. You could use #DataJpaTest annotation, it starts a in memory database. The official documentation says:
You can use the #DataJpaTest annotation to test JPA applications. By default, it configures an in-memory embedded database, scans for #Entity classes, and configures Spring Data JPA repositories. Regular #Component beans are not loaded into the ApplicationContext.
Link to the docs: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
Starting from the idea that repositories should be used only inside services and services are used to interact with the other layers of the system, I would say that testing services should be enough in the majority of cases.
I would not test standard repository methods like findAll, or findBy.., they were tested already and the purpose is not to test JPA, but rather the application.
The only repository methods that should have direct tests are the ones with custom queries. These queries may be located in a shared library and it is not efficient to write similar tests across different projects(in this case regression is a big concern)

How to disable Javers for integration tests?

I am using Javers 3.11.2 with Spring Boot 1.5.17. When I am trying to run integration tests on an embedded database I still see that Javers tables are getting created each time.
Is there a way I can disable Javers during these tests so that these tables will not be created each time?
There is the easy way, put:
javers:
sqlSchemaManagementEnabled: false
in your application-test.yml. See https://javers.org/documentation/spring-boot-integration/
Disclaimer: I've never used Javers.
In general, disabling something in "integration tests" means that you don't want to load some beans (of Javers in this case).
This means in turn that you have to exclude them from the list of configurations spring boot works with.
If you're using javers autoconfiguration module, it has to provide in its own "spring.factories" file (can be found inside the jar) a file for autoconfiguration.
Find its java code and see whether it has some "#Conditional on something (property beans, etc.)" If it has than create a profile for integration test that will configure the beans in a way that conditional in javers won't pass and the bean won't be created as a consequence
If it doesn't have a conditional on something like this, you'll have to exclude the whole configuration. Its usually can be done by annotation #SpringBootApplication(exclude=<JaversAutoconfiguration goes here>
This will, however, turn it off also for production usage, which is obviously not something that you want. So for "production" profile, you'll have to import it as a regular configuration (not an autoconfiguration), for integration test profile you won't need this.

Spring MVC: Recommended way to validate things that require existing Services/Repositories

Spring MVC offers form validation through both annotations on the forms (for example #NotNull) to do a simple check of the value of a field, and custom Validators, which help you do cross-field validations (verifying two password fields contain the same value, etc).
I am looking for the recommended way to do validations that go a bit further, however. For example verify if a username is not used already, which requires a call to the database. I assume I can simply inject my PersonRepository into the custom validator (which is an #Component) after all, but I doubt it'll be transactionally safe..or very clean.
What is the recommended way to do this, that requires the least amount of duplicated code? Or should I simply write my own validation layer, that throws some ValidationException with a list of validationmessages, which I have to map to the bindingresult?
To just clearify: Spring MVC don't offers form validation by itself. It integrates with Java Bean validation vendors (like Hibernate Validator).
You're right: If you configure LocalValidatorFactoryBean as a bean in your application context, you benefit from dependency management in your custom validators. In my opinion there is no need to implement a custom validation layer within your setup, since you already have a powerful and generic abstraction of validation which even conforms to Java standards.
If you worry about whether calling your repository in validator is transaction safe or not see http://docs.spring.io/spring-data/jpa/docs/1.8.2.RELEASE/reference/html/#transactions for details. CRUD operations are transactional by default. If you need a more sophisticated validation logic with needs a transaction context, you could either make your isValid(...) method transactional by annotating it, or you could autowire a business service with likely is transactional by itself. This perfectly integrate with the concepts of Spring.
Use the same business transaction
If you need to handle validation and business logic (check whether a user name is already used and insert a new if not) in the same transaction you could think about restricting those validations in Controller layer to the basic ones (#NotNull for example). This will ensure, that only syntactic correct requests make their way to your service layer.
In the service you will use an autowired validator and trigger the entire validation constraints manually. If you have a combination Hibernate as JPA vendor and Hibernate as Validation vendor you could even make use of the integration of both (pre persit and pre update events) which will cause the validation to occur automatically before the changes are written to the database.
However you decide, you will likely use validation groups to split the constraints into two groups 'syntactic' and 'semantic' for example. If you call the validator manually you can pass the groups you want to take into account. If you use integrated validation with Hibernate you can control the groups for the different events by specifying the following properties:
javax.persistence.validation.group.pre-persist
javax.persistence.validation.group.pre-update
If you decide for this way you will simply call your transactional business service method from your controller. Business logic and validation will participate in the same transaction this way.

What are TestExecutionListeners, and what do they do?

As far as I understand, TestExecutionListeners act like #BeforeClass methods in JUnit. What I don't understand is why I need to use DependencyInjectionTestExecutionListener, TransactionalTestExecutionListener and DirtiesContextTestExecutionListener to use DbUnitTestExecutionListener.
Normally without DbUnit, I can create and populate the database. Why suddenly do I need to use these listeners to do some CRUD for my database?
TestExecutionListeners provide various types of functionality to tests running in the Spring TestContext Framework.
If you are interested in what a particular listener does, the best way to find out is to read the Javadoc for the respective class. In addition, the Testing chapter of the Spring reference manual goes into detail about how to use each of the listeners and what they do.
In your particular case, if you're not using #DirtiesContext, then you don't need to use the DirtiesContextTestExecutionListener. As for DependencyInjectionTestExecutionListener and TransactionalTestExecutionListener, you will likely need them to inject dependencies into your test (e.g., via #Autowired, #Inject, #Resource, etc.) and for transactional tests (i.e., tests annotated with #Transactional).
Note as well that the aforementioned listeners are enabled by default. So if you've been using the Spring TestContext Framework without any custom listeners like the one for DbUnit, then you just never realized that the listeners existed. The section on TestExecutionListener configuration in the reference manual should also help clarify things. Note, however, that some features like merging and auto-detection of default listeners are only available in Spring Framework 4.1+.
Regards,
Sam (author of the Spring TestContext Framework)

Good strategy for Spring Framework end-to-end testing

So this is a rather "big" question, but what I'm trying to accomplish is the following:
I have a Spring application, MVC, JDBC (MySQL) and JSP running on tomcat.
My objective is to test the entire "stack" using a proper method.
What I have so far is Junit using Selenium to simulate an actual user interacting with the application (requires a dummy account for that), and performing different validations such as, see if element is present in the page, see if the database has a specific value or if a value matches the database.
1st concern is that this is actually using the database so it's hard to test certain scenarios. I would really like to be able to mock the database. Have it emulate specific account configs, data states etc
2nd concern is that given the fact that I use what is in the database, and data is continuously changing, it is hard to predict behavior, and therefore properly asserting
I looked at Spring Test but it allows for testing outside a servlet container, so no JSP and no Javascript testing possible.
I saw DBUtils documentation but not sure if it will help me in this case
So, to my fellow developers, I would like to ask for tips to:
Run selenium tests on top of a mocked database
Allow different configs per test
Keep compatibility with Maven/Gradle
I have started with an ordered autowire feature to support this kind of stubbing.
It's basically an idea that i took over from the Seam framework i was working with in the past but i couldnt find yet a similar thing in spring.
The idea is to have a precedence annotation (fw, app,mock,...) that will be used to resolve the current implementation of an autowired bean. This is easy already in xml but not with java config.
So we have our normal repository beans in with app precedence and a test package stubbing these classes with mock precedence.
If both are in the classpath spring would normally fail with a duplicate bean found exception. In our case the extended beanfactory simply takes the bean with the highest precedence.
Im not sure if the order annotation of spring could be used directly but i prefered to have "well defined" precedence scopes anyway, so it will be clear for our developers what this is about.
! While this is a nice approach to stub so beans for testing i would not use it to replace a database definition but rather go with an inmemory database like hsql, like some previous answers mentionned already. !

Resources