Start services manually when doing a spring boot test - spring-boot

So I have a test class annotated with #SpringBootTest
#SpringBootTest
#Slf4j
public class IntegrationTests {}
This code automatically starts two of classes in my application annotated with #service.
In my integration test I’m testing the spring scheduler to works as expected and the tests passes.
Now I want to write another test that only test one of the two services annotated with #service. The second service I want to enable and disable myself. This is because one of two services uses the springboot #scheduled annotation, which results in unpredictable logic.
So is there a way I can start a #SpringBootTest with the possibility to choose the services I need?
Thanks in advance!

Have you tried adding the test classes in #SpringBootTest? like so:
#SpringBootTest(classes = YourTestClass.class)

Related

Run custom ApplicationContextInitializer in #SpringBootTest

i try to run a custum ApplicationContextInitializer within an integration test which is annotated with #SpringBootTest. I've tried to use a combination of #SpringBootTest and #ContextConfiguration, which looks like this:
#SpringBootTest
#ContextConfiguration(
initializers = CustomContextInitializer.class
)
public class Test {
....
}
This fails because some bean construction triggered by #SpringBootTest, depends on properties which will be injected by programmaticaly logic of my CustomContextInitializer and this one is executed parallel so that this properties aren't available at this point.
Is there a solution for this situation? Could the CustomContextInitializer run before the initalisation procedure triggered by #SpringBootTest?

how to run springboot test without run tomcat?

I am developing a spring boot application and write some junit test.
But I find when I run any tests, tomcat is also started up, It makes those tests very slow and waste many times.
When I develop a SpringMvc application, junit test can run without start tomcat, It saves many times.
So, I want to ask it there anyway to run springboot test with out start tomcat?
Running a test with #SpringBootTest does not start an embedded server by default.
By default, it runs in the MOCK environment.
By default, #SpringBootTest will not start a server. You can use the
webEnvironment attribute of #SpringBootTest to further refine how your
tests run:
MOCK(Default) : Loads a web ApplicationContext and provides a mock web
environment. Embedded servers are not started when using this
annotation. If a web environment is not available on your classpath,
this mode transparently falls back to creating a regular non-web
ApplicationContext. It can be used in conjunction with
#AutoConfigureMockMvc or #AutoConfigureWebTestClient for mock-based
testing of your web application.
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
I guess what you wanted to achieve could be achieved by Slice Test concept. In general, you don't need a full-fledged mock environment or environment with an embedded server with all the configured beans in the spring container when you are performing unit tests.
For e.g. you have to unit test your Controller then you have #WebMvcTest annotation in place that will configure only web related beans and ignore the rest of the beans.
To test whether Spring MVC controllers are working as expected, use
the #WebMvcTest annotation. #WebMvcTest auto-configures the Spring MVC
infrastructure and limits scanned beans to #Controller,
#ControllerAdvice, #JsonComponent, Converter, GenericConverter,
Filter, WebMvcConfigurer, and HandlerMethodArgumentResolver. Regular
#Component beans are not scanned when using this annotation.
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests
Similarly, for the database layer, there is #DataJpaTest
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test
Long story short: when you intend to do unit testing with Spring framework, slice test is the one you should use in most of the cases.
If you are placing the following annotations, this will start the embedded container...
#RunWith(SpringRunner.class)
#SpringBootTest
Because, if you see the SpringBootTestContextBootstrapper.class class , this has been invoked the container which is invoked by #BootstrapWith(SpringBootTestContextBootstrapper.class) when we specify #SpringBootTest
You can remove those and can do as follows:
import org.junit.Test;
public class HellotomApplicationTests {
#Test
public void contextLoads() {
}
}
R-Click and RunAs Junit
O/P

How to speed up unit tests with less configuration

The unit test template of jhipster is great, but sometime, especially, during coding, I need to write unit test code and run frequently. But now the unit test will start tomcat container and many other module, which I don't need if I want to test a service function.
Now the test class is like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
#Transactional
public class SomeClassTest {
.....
How can I modify it to only initialize spring container and DB? Thanks.
If you do not need the server, don't make your test an integration test. If you remove #WebAppConfiguration and #IntegrationTest spring boot will start a regular (i.e. non-web context) and will not start Tomcat.
If you need to go even further, you can disable certain features, either via application-test.properties + #ActiveProfiles("test") to disable stuff via config or using the exclude parameter of #SpringBootApplication (or #EnableAutoConfiguration) as Lukas said already.
Take a look at this question How to exclude *AutoConfiguration classes in Spring Boot JUnit tests? and see if this helps you. The idea is to explicitly exclude auto configurations that you don't need in your test, so in your case it would probably be EmbeddedServletContainerAutoConfiguration

What does this do: #RunWith(SpringJUnit4ClassRunner.class)

What does this annotation do?
When would I want to use it?
When would I not want to use it?
#RunWith(SpringJUnit4ClassRunner.class)
I can find more usages of this when I Google and do not find a 101 explanation as to what this annotation is supposed to communicate to me or when/why I would use it?
The annotation is used to configure a unit test that required Spring's dependency injection.
From Spring Reference - 10. Unit Testing:
10.1 Creating a Unit Test Class
In order for the unit test to run a batch job, the framework must load the job's ApplicationContext. Two annotations are used to trigger this:
#RunWith(SpringJUnit4ClassRunner.class): Indicates that the class should use Spring's JUnit facilities.
#ContextConfiguration(locations = {...}): Indicates which XML files contain the ApplicationContext.
If you are using annotations rather than XML files, then any class that you are unit testing that requires Spring dependency injection needs to be put into the #ContextConfiguration annotation. For example:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = FooManager.class)
class FooManagerTest {
#Autowired
FooManager fooManager;
Now when you use fooManager in a unit test it will have have a Spring context setup for it.
If fooManager autowires in any beans then those bean's classes also need to be in the #ContextConfiguration annotation. So if fooManager autowires in a FooReporter bean:
#ContextConfiguration(classes = {FooManager.class, FooReporter.class})
If the beans that fooManager autowires in contain state, then you will likely want to reset the state of those beans for each test. In that case you can add the #DirtiesContext annotation to your test class:
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
If fooManager or any of its autowired beans reads Spring config then you need to add an initializers list to the #ContextConfiguration annotation, that contains the ConfigFileApplicationContextInitializer class:
#ContextConfiguration(classes = {FooManager.class, FooReporter.class}, initializers = ConfigFileApplicationContextInitializer.class)
To answer the when you would and wouldn't want to use it part of the question.
When to use SpringJUnit4ClassRunner
IMO SpringJUnit4ClassRunner should be used very sparingly. There is a significant overhead involved with starting up a Spring container to run a unit test.
I typically use SpringJUnit4ClassRunner to test:
that components are injected (auto-wired) as expected
that configuration data is injected as expected
When you are injecting components issues can arise if the #Qualifier annotation is not used or used incorrectly, for example.
When loading configuration from multiple yaml files you may want to test that maps are being merged as expected, with the appropriate overrides occurring.
At the very least I always have a simple SpringJUnit4ClassRunner test as a sanity check that the Spring container starts up OK.
When not to use SpringJUnit4ClassRunner
I would not use SpringJUnit4ClassRunner to test the non-Spring related functionality in my code under test. Which in my experience means most of the functionality.
So this means that any autowired components and injected config data needs to be mocked. This can mean quite a bit of setup code for your unit tests. However this setup code only needs to be written once for all the tests in your class under test. It is also much quicker to run unit tests with mocked components.
I keep the mocking simple and use Spock to mock the components. Example groovy code:
import spock.lang.Specification
class FooManagerTest extends Specification {
FooManager cut
void createMockFooReporter() {
FooReporter mockFooReporter = Mock(FooReporter)
mockFooReporter.fooFormatter = Mock(FooFormatter)
}
void setup() {
cut = new FooManager()
cut.fooReporter = createMockFooReporter()
}
void "Basic test"() {
// Do a basic test using 'cut'
}
}
In this example the class under test FooManager has an autowired FooReporter which itself contains an autowired FooFormatter.
I think #RunWith annotation is in order to initialize the context of spring. Because the junit5 is released, you just can replace it with #SpringJUnitConfig.By the way, #RunWith annotation is already replaced by #ExtendWith, but you still can use it.

Using Spring #ActiveProfile in integration tests

I am using #Profile Spring annotations to choose between embedded, standalone and container managed data sources. In order to choose 'embedded' my integration tests are annotated to activate the appropriate profile:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={TestConfigWrapper.class})
#ActiveProfiles({"EMBEDDED_DB"})
public class SomeIntegrationTest {
The problem is that I would like to move '#ActiveProfiles' into TestConfigWrapper, but doing this doesn't get picked up and the application context won't load any DataSources.
This means I have to annotate every integration test with an #ActiveProfile which effectively means it becomes integration test boiler-plate and could easily hamper future refactoring.
Is there a way I can do this using java config?
Per comment from Hippooom use an abstract class to configure tests:
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={WebAppInitializer.class})
#ActiveProfiles({Profiles.EMBEDDED_DB})
public abstract class ProfiledIntegrationTest {
}

Resources