spring-boot/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto/testing.adoc

107 lines
5.5 KiB
Plaintext

[[howto.testing]]
== Testing
Spring Boot includes a number of testing utilities and support classes as well as a dedicated starter that provides common test dependencies.
This section answers common questions about testing.
[[howto.testing.with-spring-security]]
=== Testing With Spring Security
Spring Security provides support for running tests as a specific user.
For example, the test in the snippet below will run with an authenticated user that has the `ADMIN` role.
include::code:MySecurityTests[]
Spring Security provides comprehensive integration with Spring MVC Test and this can also be used when testing controllers using the `@WebMvcTest` slice and `MockMvc`.
For additional details on Spring Security's testing support, see Spring Security's {spring-security-docs}/servlet/test/index.html[reference documentation].
[[howto.testing.testcontainers]]
=== Use Testcontainers for Integration Testing
The https://www.testcontainers.org/[Testcontainers] library provides a way to manage services running inside Docker containers.
It integrates with JUnit, allowing you to write a test class that can start up a container before any of the tests run.
Testcontainers is especially useful for writing integration tests that talk to a real backend service such as MySQL, MongoDB, Cassandra and others.
Testcontainers can be used in a Spring Boot test as follows:
include::code:vanilla/MyIntegrationTests[]
This will start up a docker container running Neo4j (if Docker is running locally) before any of the tests are run.
In most cases, you will need to configure the application to connect to the service running in the container.
[[howto.testing.testcontainers.service-connections]]
==== Service Connections
A service connection is a connection to any remote service.
Spring Boot's auto-configuration can consume the details of a service connection and use them to establish a connection to a remote service.
When doing so, the connection details take precedence over any connection-related configuration properties.
When using Testcontainers, connection details can be automatically created for a service running in a container by annotating the container field in the test class.
include::code:MyIntegrationTests[]
Thanks to `@Neo4jServiceConnection`, the above configuration allows Neo4j-related beans in the application to communicate with Neo4j running inside the Testcontainers-managed Docker container.
This is done by automatically defining a `Neo4jConnectionDetails` bean which is then used by the Neo4j auto-configuration, overriding any connection-related configuration properties.
The following service connection annotations are provided by `spring-boot-test-autoconfigure`:
- `@CassandraServiceConnection`
- `@CouchbaseServiceConnection`
- `@ElasticsearchServiceConnection`
- `@InfluxDbServiceConnection`
- `@JdbcServiceConnection`
- `@KafkaServiceConnection`
- `@MongoServiceConnection`
- `@Neo4jServiceConnection`
- `@R2dbcServiceConnection`
- `@RabbitServiceConnection`
- `@RedisServiceConnection`
As with the earlier `@Neo4jConnectionDetails` example, each can be used on a container field. Doing so will automatically configure the application to connect to the service running in the container.
[[howto.testing.testcontainers.dynamic-properties]]
==== Dynamic Properties
A slightly more verbose but also more flexible alternative to service connections is `@DynamicPropertySource`.
A static `@DynamicPropertySource` method allows adding dynamic property values to the Spring Environment.
include::code:/MyIntegrationTests[]
The above configuration allows Neo4j-related beans in the application to communicate with Neo4j running inside the Testcontainers-managed Docker container.
[[howto.testing.slice-tests]]
=== Structure `@Configuration` classes for inclusion in slice tests
Slice tests work by restricting Spring Framework's component scanning to a limited set of components based on their type.
For any beans that are not created through component scanning, for example, beans that are created using the `@Bean` annotation, slice tests will not be able to include/exclude them from the application context.
Consider this example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/howto/testing/slicetests/MyConfiguration.java[]
----
For a `@WebMvcTest` for an application with the above `@Configuration` class, you might expect to have the `SecurityFilterChain` bean in the application context so that you can test if your controller endpoints are secured properly.
However, `MyConfiguration` is not picked up by @WebMvcTest's component scanning filter because it doesn't match any of the types specified by the filter.
You can include the configuration explicitly by annotating the test class with `@Import(MyConfiguration.class)`.
This will load all the beans in `MyConfiguration` including the `BasicDataSource` bean which isn't required when testing the web tier.
Splitting the configuration class into two will enable importing just the security configuration.
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/howto/testing/slicetests/MySecurityConfiguration.java[]
----
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/howto/testing/slicetests/MyDatasourceConfiguration.java[]
----
Having a single configuration class can be inefficient when beans of a certain domain need to be included in slice tests.
Instead, structuring the application's configuration as multiple granular classes with beans for a specific domain can enable importing them only for specific slice tests.