I am trying to test Springboot main class for code coverage with junit5. But i am getting:
org.postgresql.util.PSQLException: Connection to 127.0.0.1:5432
refused.
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.jupiter.api.Assertions.*;
#SpringBootTest
#RunWith(SpringRunner.class)
class AlphaApplicationTest {
#Test
void main() {
assertDoesNotThrow(() -> AlphaApplication.main(new String[] {}));
}
}
Firstly, you tagged the question with junit5, so I assume you are using Junit5.
With v5, you shouldn't use the #RunWith annotation ([source])1
Secondly, you should not run your main method in the test! The SpringBootTest annotation already starts everything! Please read the documentation on testing Spring Boot Applications. When you generate a new project with start.spring.io, it will provide you with a basic unit test, which starts an application context. It should look just like this:
// Includes omitted for brevity
#SpringBootTest
class AlphaApplicationTest {
#Test
void contextLoads() {
}
}
That's all. The rest is Spring "magic".
For more, see the Spring Guides on testing, e.g., "Testing the Web Layer"
Also, for testing you usually don't want to use the "real" database. Spring Boot comes with some auto-configuration to use an H2 In-Memory-Database for testing. All you need to do is include the relevant dependencies in your POM:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
You can also use normal Spring Boot configuration for this, by using an applications.properties only for tests in test/resource/application-test.properties
Related
#ExtendWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes= CommunityApplication.class)
it said
Incompatible types. Found: 'java.lang.Class<org.springframework.test.context.junit4.SpringRunner>', required: 'java.lang.Class<? extends org.junit.jupiter.api.extension.Extension>[]'
then I added codes in the pom.xml:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>4.12</version>
</dependency>
then it said
Package 'junit:junit' can be upgraded to version '4.13.2'
I think you are misusing the annotations.
#RunWith(SpringRunner.class)
This one is used just to enable spring boot features. (#Autowire, #mockbean). It is the bridge between unit tests and spring boot test features used for testing. When you need to test those Spring Boot associated elements, you use this annotation.
#SpringBootTest
This one is used for integration testing. It loads a complete application context which is used for end-to-end testing.
You used not mix up these 2 annotations.
I am currently working on Microservices and this project is basically a library and it does not have a main function. I am writing Unit test cases for this library, but I am getting unable to find #SpringBootConfiguration. If there is no main function, can't we execute the Unit test cases ?
The only file in the library
class OnlyFile {
void validate(){
}
}
Testing
#SpringBootTest
class MyTest {
#Test
void testIt(){
//
//
}
}
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.3.RELEASE</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
If you want to write and run unit tests and it is only a library, then I don't think it is neccesary for you to have #SpringBootTest annotation on your test class. It is used for integration testing, when you need to have a spring application context in your integration test.
When running integration tests in a class annotated with #SpringBootTest, then you need to have a class in same package or subpackage as the test class annotated with #SpringBootConfiguration, which contains the configuration to load the application context. The class could be empty if you don't need to customize the configuration. Alternatively, you can specify which components to use when loading the application context like this
#SpringBootTest(classes = ...)
I am trying JUnit 5 and Cucumber at Spring Boot 2.2.6 and will need both BDD scenarios and unit tests at my application. I have created a dummy ping controller corresponding feature file which are OK.
Cucumber tests are not called when I run mvn clean test. Only JUnit test is called. However, I can run Cucumber scenarios from Intellij GUI when click on the Run Test button for CucumberTest.java.
Here are my classes:
DummyApplicationTests.java:
package com.a.dummy;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
#SpringBootTest
#ActiveProfiles("test")
public class DummyApplicationTests {
#Test
public void contextLoads() {
}
}
CucumberTest.java:
package com.a.dummy.bdd;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(features = "src/test/resources/features")
public class CucumberTest {
}
CucumberSpringContextConfiguration.java:
package com.a.dummy.bdd;
import com.a.dummy.DummyApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
#ContextConfiguration(classes = DummyApplication.class)
public abstract class CucumberSpringContextConfiguration {
}
PingTest.java:
package com.a.dummy.bdd.steps;
import com.a.dummy.bdd.CucumberSpringContextConfiguration;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class PingTest extends CucumberSpringContextConfiguration {
#When("^the client calls /ping")
public void the_client_issues_GET_ping() {
...
}
#Then("^the client receives status code of (\\d+)$")
public void the_client_receives_status_code_of(int statusCode) {
...
}
#And("^the client receives ping response")
public void the_client_receives_ping_response_body() {
...
}
}
What I am missing?
If you just upgraded to Spring 2.4.0 and maven doesn't run you integration tests, it's because:
Cucumber is based on JUnit 4. If you’re using JUnit 5, remember to
include junit-vintage-engine dependency, as well. For more
information, please refer to JUnit 5 documentation.
Cucumber documentation
From Spring Boot 2.4.0 reference you can fix it as follows:
If you have tests that use JUnit 4, JUnit 5’s vintage engine can be
used to run them. To use the vintage engine, add a dependency on
junit-vintage-engine, as shown in the following example:
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
JUnit 5 support has not yet integrated and I had to include junit-vintage due to RunWith is a Junit 4 annotation.
A 2021 answer could be to add
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${cucumber.version}</version>
</dependency>
to your pom.xml file as this allows Cucumber to work with Junit 5. See also https://github.com/cucumber/cucumber-jvm/blob/main/junit-platform-engine/README.md for more ideas.
I have had the same issue with Spring boot 2.4.0 because it only supports JUnit 5, and seems like Cucumber only integrates with JUnit 4 (RunWith). Go back to Spring boot 2.3.6 (which has backwards compatibility with JUnit 4) solved the issue.
https://docs.spring.io/spring-boot/docs/2.3.6.RELEASE/reference/html/spring-boot-features.html#boot-features-testing
26.1. Test Scope Dependencies The spring-boot-starter-test “Starter” (in the test scope) contains the following provided libraries:
JUnit 5 (including the vintage engine for backward compatibility with
JUnit 4): The de-facto standard for unit testing Java applications.
I have split a project, based on Spring Boot, into several Maven modules. Now only the war-project contains a starter class (having a main method, starting Spring), the other modules are of type jar.
How do I test the jar projects, if they don't include a starter?
Example JUnit test case header:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(StarterClassInDifferentProject.class)
...
I think context tests should be available per module so you can find issues with wire and configuration early on and not depend on your full application tests to find them.
I worked around this issue with a test application class in the same module.
Make sure this main class is in your test dir.
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
your context should work now.
#RunWith(SpringRunner.class)
#ActiveProfiles(profiles = {Profiles.WEB_REST})
#WebMvcTest(EntityController.class)
#DirtiesContext
public class ServicesControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private Controller controller;
#Test
public void testAll() throws Exception {
given(controller.process(null)).willReturn(null);
mvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
I solved a similar situation.
I have a project with two modules:
a "lib" project with domain and utilities classes,
a "web" projects with a spring boot application, templates, controllers, etc...
and I wanted to test the "lib" project in a spring-boot-test fashion.
First, include the required dependencies with scope "test" in the pom.xml (in my case there is also the H2 database):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.3.3.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- add also add this here, even if in my project it is already present as a regular dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.3.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
<scope>test</scope>
</dependency>
For testing purposes, among the test sources of the "lib" project, I have a class that acts as my test configuration
package my.pack.utils;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#TestConfiguration
#EnableJpaRepositories(basePackages = {"my.pack.engine.storage", "my.pack.storage"})
#EntityScan(basePackages = {"my.pack.storage", "my.pack.entity"})
#EnableAutoConfiguration
public class MyTestConfiguration
{
}
This sets up the H2 database in order to test the data access functionalities of the application
Finally, only in the test classes where I find it useful, I configure the execution to use the test configuration (I do not always need to do that, but sometimes it is handy):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyTestConfiguration.class)
public class TestAClassThatNeedsSpringRepositories
{
// tests...
}
The question is
How do I test the jar projects, if they don't include a starter?
I believe the right answer, is that your jar submodules should not be united tested with spring-boot context.
In fact, most if not all tests in your jar projects should not even use the RunWith(Spring...)
They should be vanilla or using a mock library such as #RunWith(MockitoJUnitRunner.class).
If you read SpringApplicationConfiguration's javadoc:
Class-level annotation that is used to determine how to load and configure an ApplicationContext for integration tests.
It is considered integration testing.
Other than that, you can also launch your tests using spring context (not spring-boot) with a 'test spring configuration' in your jar submodule. Define your beans/resources and use it in your test.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(TestConfigInJarModule.class)
For instance, I do this to test Spring data Repositories, using a test spring configuration (without dependencies on spring-boot).
I have multi module projects; I am creating Junit Test classes for testing purpose.
But the problem is, when I run my Core Project Test using only 2 package ComponentScan for testing. It is not able to locate Util Project Test config.(Test package get excluded while building JAR)
Because of this, I am getting, No qualifying bean of type exception as Configuration class is missing from Util project.
#SpringBootApplication
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = { CreateProfileTest.class })
#ComponentScan({"com.myproject.testconfig","com.myproject.module"})
#EnableAutoConfiguration
public class CreateProfileTest {
#Test
public void myMethod()
{
}
}
So, How I can gain access to Util Project Test Config in Core Project Test.
Job - > Core -> Util (Here Core is depend on Util)
Now
CoreProject/
src/main/com.myproject.config
src/main/com.myproject.module
src/test/com.myproject.testconfig
UtilPorject/
src/main/com.myproject.config
src/main/com.myproject.module
src/test/com.myproject.testconfig
Please let me know, If there is any alternative way to achieve this or if I am doing anything wrong here.
I am using Maven and Spring Boot.
It seems to me this is a matter of classpath. Have you tried adding this in the CoreProject pom.xml ?
<dependency>
<groupId>...</groupId>
<artifactId>util-project</artifactId>
<version>...</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>