SpringBoot Test - possible to run tests against the default application context? - spring

Execution of the JUnit test of a Spring Boot application causes a testing context of the application to be started whenever the test is invoked. Is there a way to run this test against a spring boot application that has already started without having to spin up a second application context for the test? For example, can the testing framework be instructed to use an existing application context that has already been launched?
#SpringBootTest
#RunWith(SpringRunner.class)
public class MyAppTests {
#Autowired
public SomeService someService;
#Test
public void testInjection() throws AssertionError {
Assert.assertTrue(someService != null);
}
}

There is No way to run tests just using an already started application context, meanwhile without launching a second testing application, if on the premise that you describe.
It means JUnit test of a Spring Boot application is a kind of whitebox testing, the test case will only runs in the environment which is started by itself. The test case has nothing to do with other already running application context.
However, if you really want to run tests against a spring boot application (just like a running test environment) that has already started, maybe you could try some other blackbox testing, for example, API testing or GUI testing. But it will not allow you test SomeService class directly.

Update you test class as below and it should fix your problem.
#SpringBootTest
#RunWith(SpringRunner.class)
#SpringApplicationConfiguration(classes = YourApplication.class)
#ActiveProfiles(Constants.SPRING_PROFILE_DEVELOPMENT)
public class MyAppTests {

Related

Are the project beans already instantiated when we try to run a junit test in spring boot

I am new to Spring and spring boot.
For my spring boot application which is a rest controller, I have some beans along with my data source.
I use my data source to create jdbc template. Now when I am in my rest controller code, I have all these beans #Autowired and they work perfectly fine.
My query is regarding the junit testing part.
When I write my test code inside src/test/java and when I execute my test class within IDE, are the beans defined in my src/main/javacode, instantiated before test case execution?
You might use the same container, or instantiate another container particularly for testing purposes, for which you'll provide a configuration of that other Spring Container separately:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:test-context.xml")
public class SomeClassTest{...}
However, you can also enable support for loading your Application Context and then use the #Autowired fields in your JUnit fixtures, which also works fine too:
#RunWith(SpringRunner.class)
public class SomeTestClass {
....
#Autowired
ApplicationContext context;
....
}
From here, you can get any bean you wish.

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 start server once before and stop after all tests?

I want to start a server once before all tests and then shutdown the server after all tests have executed.
In Spring Boot 1.3, I could create a #Component with #PostConstruct to start a server once before tests were executed and then #PreDestroy to stop the server after all tests executed.
After upgrading to Spring Boot 1.5, #PostConstruct is called before every #Test method. #PreDestroy is called for every #Test but only after all tests have executed!
What changed and/or how should I be doing it now?
Similar question with answer - https://stackoverflow.com/questions/42839765/can-you-get-spring-boot-junit-tests-to-use-the-same-server
Apparently, I was being smart while upgrading and changed my WebEnvironment to use RANDOM_PORTs. This causes the Context Caching to be unique for each test class which in turn causes the #Component to be recreated each test.
Thanks

How to ensure load time weaving takes place for Eclipselink when using SpringBootTest with other tests running beforethe Spring one

I'm using Spring Rest Docs to generate documentation for my REST services. This involves running unit(strictly integration) tests that run against a live Spring Boot Container that is kicked off by the test. The test class looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MySpringConfiguration.class)
#WebAppConfiguration
public class ApiDocumentation {
private MockMvc mockMvc;
#Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");
#Autowired
private WebApplicationContext context;
#Autowired
private ObjectMapper objectMapper;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation))
.build();
}
#Test
public void testSomething() throws Exception {
}
}
The application uses JPA with EclipseLink for the EntityManager implementation.
When I run the test standalone in my IDE or as the only test present when I run a Maven build using the maven-surefire-plugin everything works fine.
However it's not the only test I want to run in the suite. As soon as I run other tests in the suite I come across the issue mentioned here, namely
"Spring's agent does not initialize the persistence context until the application accesses the Spring context. If the application has already triggered the loading of the persistent class before accessing the Spring context, weaving will not occur."
and get errors like this:
Exception Description: The method [_persistence_set_someField_vh] or [_persistence_get_someField_vh] is not defined in the object [mypackage.MyEntity].
So what do people normally do to get around this ? Run SpringBootTest classes in a different module to unit tests that access entities ?
As far as I concerned problem caused by dynamic weaving, if you make it static it should work proper. Possibly it could help you
Another solution could be to disable dynamic weaving in that particular test using eclipselink.weaving JPA property.
See this question and its answers: #SpringBootTest interferes with EclipseLink dynamic weaving

How to configure to run the springboot tests against an already up and running service on a different location

I have to configure my integration tests to run against the service that is up and running in a different location.Currently my tests are for localhost and they are starting the service by the below annotations defined in a parent class :
#SpringApplicationConfiguration(classes =ServiceApplication.class)
#WebAppConfiguration
#IntegrationTest("server.port:8084")
In the child classes this is how I have configured my tests to get the port and endpoint to run the tests :
#RunWith(SpringJUnit4ClassRunner.class)
public class RunningIntegrationIT extends BaseTestService {
#Value("${local.server.port}")
int port;
private String uri = "/service/firstName";
#Before
public void setup() {
RestAssured.port = port;
}
Now if I have to make the tests run against the service already running on a different ipaddress and port then how to configure that setting. Seems like if I use the #IntegrationTest it starts the spring-boot tomcat by default.
Also I have read to use the #ActiveProfile but can someone give me details on how to use this annotation.
local.server.port has local in it. You can't just use that to refer to a different process that you expect to run. Your tests becomes pure client test so maybe they should not even use spring boot at all.
What auto-configuration piece are you using in your test? Maybe using Spring Boot there doesn't bring much?
I understand you may want to share the same test suite between a service that Spring Boot would start and a remote instance. That's fine: just write your test in an abstract class and have two implementations. The full remote one may not even use Spring Boot.

Resources