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 = ...)
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 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
When I try to run tests with tag filtering, only those marked with #Test from JUnit 5 are executed but not those marked with #Test from JUnit 4.
The point is that if the filtering expression is "!slow", it actually executes tests without the tag "slow" regardless which #Test annotation is used. But when I filter with the expression "slow", tests with this tag won't be executed if they have the #Test from JUnit 4.
I know I could change to the new annotation when adding a tag but it would be nice not to have to do that for the tests I already have.
I have this imported into my pom
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
And the test I am trying to run is
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Tag;
public class Test {
#org.junit.Test
#Tag("slow")
public void test() {
assertTrue(true);
}
}
You can't mix JUnit 4 and JUnit 5 annotations in the same test. So your approach will not work. A solution might be to migrate these tagged tests to JUnit 5.
Background: The JUnit Platform uses different test engines to discover and execute tests. The junit-vintage-engine can handle tests written against the JUnit 4 API, where test methods are annotated with #org.junit.Test. The junit-jupiter-engine can handle tests written against the JUnit Jupiter API (commonly known as JUnit 5), where test methods are annotated with #org.junit.jupiter.api.Test. Each engine only has knowlegde about their discovered test methods. The junit-vintage-engine doesn't have any behaviour for JUnit Jupiter annotations, so these annotations are simply ignored.
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'm building my package with maven (runs without problems) and then I try to make a Mockito test for a class.
Dependencies in the pom.xml are as follows:
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.0.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
The mockito-test looks like this:
package Person;
import static org.mockito.Mockito.*;
import java.io.IOException;
public class AppTest {
public void test() throws IOException{
PersonManagement mockedPM = mock(PersonManagement.class);
//automatically creates an instance variable of type person
mockedPM.updatePerson("test","test");
//updates this.person
verify(mockedPM).updatePerson("test","test");
}
}
After launching mvn package the test results show, that no test were run (the file including the test is found and recognized, because when I put syntax mistakes there, compiler recognizes these)
I would appreciate any help, thanks
Mockito is not a testing framework. It's a mocking API. Use JUnit or TestNG. These are testing frameworks. Both simply require some annotations to be placed on test methods.
And of course, your JUnit or TestNG tests will use the Mockito API internally, to mock dependencies.
Mockito is a framework for mocking objects, while JUnit is a framework for unit testing.
it looks like you are experimenting with how it works. I would suggest starting by reading up on JUnit, and when you feel you have it under control, go back to how mocking works.
this is a dependency for JUnit:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.6</version>
</dependency>
after adding and importing this you can annotate tests with #Test
#JB Nizet told you the correct answer. You need to annotate the method with #org.junit.Test