JUnit tests SpringJUnit4ClassRunner - java

#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:spring/integration-test.xml"
})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class TestClass {
#Autowired
private Dao dao;
#Test
#Transactional
public void test1() {
}
}
Hello!
I'm trying to start single test method from Spring Tool Suite Debug configurations and I have an exception:
java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=test1], {ExactMatcher:fDisplayName=test1(com.org.TestClass )], {LeadingIdentifierMatcher:fClassName=com.org.TestClass ,fLeadingIdentifier=test1]] from org.junit.internal.requests.ClassRequest#302e67
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:40)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:77)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:68)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:43)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:444)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
But since I remove #RunWith(SpringJUnit4ClassRunner.class) at this example the test method launched successfully.
I would appreciate any useful advice to eliminate this trouble.
Thank you.
I have spring version 3.1.1
Here are imports:
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import org.testng.annotations.Test;

It is cause spring configuration specific works.
Spring created proxy instance for your class because of #Transactional annotation under your test method, and after that method doesn't contain #Test annotation.
Please see information about spring proxy there: https://spring.io/blog/2012/05/23/transactions-caching-and-aop-understanding-proxy-usage-in-spring
Do you really need #Transactional annotation under your test method?
You can create class-helper only for testing, write #Transactional annotated methods there, inject it (annotation #Autowired) and use in your test class

Related

NullPointerException when mocking repository JUnit

I have created a basic Rest API with a Controller, Service and Repository layer. I am now trying to write a unit test for the Service layer method that finds product by the product id. However, when I run the test it throws a NullPointerException in the line where I am trying to mock the repository findById() method.
The getProductById() method in the service layer is as follows:
public Product getProductById(String id){ return productRepository.findById(id).orElse(null); }
My test class for the service layer:
package com.product.Services;
import com.product.Entities.Product;
import com.product.Repositories.ProductRepository;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
class ProductServiceTest {
#InjectMocks
ProductService productService;
#Mock
ProductRepository productRepository;
#Test
void getProductById() throws Exception {
Product product = new Product();
product.setId("001");
product.setName("TV");
product.setPrice(999.99);
when(productRepository.findById("001").orElse(null)).thenReturn(product);
assertEquals(product,productService.getProductById("001"));
}
}
Attaching a picture of what the debugger shows:
The problem is that 2 different versions of JUnit are used here:
org.junit.jupiter.api.Test is from JUnit5, while
org.junit.runner.RunWith is from JUnit4.
RunWith does not exist anymore in JUnit5.
In this specific case, I would use JUnit4 - i.e. use the annotation org.junit.Test (instead of org.junit.jupiter.api.Test) to annotate your test.
How to use Mockito with JUnit5 provides other valid solutions.
JUnit 5 uses #ExtendWith(SpringExtension.class) annotation, can you change #RunWith annotation and try again?
You should mock the findById call, not the expression chained with orElse:
when(productRepository.findById("001")).thenReturn(product);

Test annotated with #DataJpaTest not autowiring field annotated with #Autowired

I have a Spring Boot app which contains a Spring Data Jpa repository. I need to run a unit (or component?) test around this repository. I do not have a lot of experience with Spring Data Jpa.
Here's my test. It's trivially simple, and I cannot get it to pass.
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import static org.junit.Assert.assertNotNull;
#DataJpaTest
public class FooRepositoryTest {
#Autowired
private FooRepository fooRepo;
#Test
public void notNull(){
assertNotNull(fooRepo);
}
}
Here's the other relevant source code.
import com.fedex.dockmaintenancetool.webservice.types.Foo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface FooRepository extends JpaRepository<Foo, Long> {
}
and
import javax.persistence.Entity;
#Entity
public class Foo {
}
I am just trying to get a Jpa repo autowired into a test, and I can't. Clearly I'm misunderstanding some small nuance of how Spring Boot works. But even after going through some tutorials, I cannot figure out what I'm missing. Could anyone help me with this?
When you use the annotation #DataJpaTest , it means that you are trying to test only the repository layer. The annotation is used to test JPA repositories and is used in combination with #RunWith(SpringRunner.class) to enable populating the application context. The #DataJpaTest annotation disables full auto-configuration and applies only configuration relevant to JPA tests.So as #fap siggested use it like :
#RunWith(SpringRunner.class)
#DataJpaTest
public class FooRepositoryTest {
#Autowired
private FooRepository fooRepo;
#Test
public void notNull(){
assertNotNull(fooRepo);
}
}
When you use the annotation #RunWith(SpringRunner.class) the SpringRunner provides support for loading a Spring ApplicationContext and having beans #Autowired into your test instance.
You're missing the #RunWith(SpringRunner.class) annotation that tells JUnit to actually start a Spring application for the test.
Your test class should look like
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertNotNull;
#RunWith(SpringRunner.class)
#DataJpaTest
public class FooRepositoryTest {
#Autowired
private FooRepository fooRepo;
#Test
public void notNull(){
assertNotNull(fooRepo);
}
}
The JUnit version used in the question is still JUnit 4.
Spring Boot 2.2.0 switches to JUnit5.
With JUnit5 you'll have to use #ExtendWith(SpringExtension.class) instead of #RunWith(SpringRunner.class). Since #JpaTest is already annotated with #ExtendsWith you don't have to actually include it though, see https://stackoverflow.com/a/65359510/4266296.

Junit5 Spring Boot Autowire ComponentScan Not Working

My problem: if my test refers to an #Bean declaration in the class listed in #SpringBootTest, autowire works. If it refers to a class automatically #ComponentScanned by the class listed in #SpringBootTest, autowire fails. Outside of testing, my app starts without autowire or componentscan issues, and I can confirm that the service I want to load in my test runs fine from non-test. I'm frustrated as hell. Am I broken, or is Junit5 functionality on Spring Boot 2?
My Test:
#ExtendWith(SpringExtension.class)
#SpringBootTest (classes=MyConfig.class)
public class MyTest {
// fails to autowire
#Autowired
private MyService _mySvc ;
// succeeds!
#Autowired #Qualifier ( "wtf" )
private String _wtf ;
MyConfig:
#EnableWebMvc
#SpringBootApplication ( scanBasePackages = "my.packaging" )
#Configuration
public class MyConfig {
#Bean
public String wtf ( ) { return "W T F???" ; }
// No #Bean for MyService because component scan is nicer in the non-test world
I had the same issue with autowiring not working although the test was starting and the problem was that I was still using the old junit4 #Test annotation.
Make sure your test method is annotated with #Test from juni5 package org.junit.jupiter.api.Test.
I think because you have annotated as such:
#SpringBootTest (classes=MyConfig.class)
Spring will only look in MyConfig.class for the appropriate beans and is not able to find one for MyService, however, I presume that Spring will scan all packages for a bean when the application is running normally. This is why it works fine in non-test.
Like #Tudro said, org.junit.jupiter.api.Test is for Junit 5. org.junit.Test is for Junit 4.
Use this below:
#ExtendedWith(SpringExtension.class)
#SpringBootTest
Maybe you could add #ContextConfiguration(classes = ApplicationConfiguration.class)
It would look like this
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import example06.junit.group01.Piano;
#SpringBootTest
#ContextConfiguration(classes = ApplicationConfiguration.class)
public class ApplicationConfigurationTest {
#Autowired
private Piano piano;
#Test
public void shouldTestPiano() {
System.err.println("Testing JUnit5 > " + piano);
}
}
My config is a simple class
#Configuration
#ComponentScan
public class ApplicationConfiguration {
}

Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean

I have a new springboot application I am attempting to get started.
The error I receive is
org.springframework.context.ApplicationContextException: Unable to start reactive web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean.
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.onRefresh(ReactiveWebServerApplicationContext.java:76) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
src/main/java/bubbleshadow/RootController.java
package bubbleshadow;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
#RestController
public class RootController {
public RootController() {
}
#GetMapping("/")
public Mono<HttpStatus> returnOk() {
return Mono.just(HttpStatus.OK);
}
}
src/test/java/test/bubbleshadow/RootControllerTest.java
package test.bubbleshadow;
import bubbleshadow.RootController;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
// import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes=RootController.class, webEnvironment = WebEnvironment.RANDOM_PORT)
#AutoConfigureWebTestClient
public class RootControllerTest {
#Autowired
WebTestClient webTestClient;
#Test
public void baseRouteShouldReturnStatusOK() {
webTestClient.head().uri("/").exchange().expectStatus().isOk();
}
}
Your configuration is not sufficient for reactive tests.
The reactive WebTestClient as well as ReactiveWebApplicationContext need reactive server in the application context. Add annotation #EnableAutoConfiguration to your RootControllerTest and let Spring's do it for you.
The autoconfiguration searches your class path and after find reactive classes and reactive context then create ReactiveWebServerFactory bean.
I assume you are using maven to get your dependencies.
I solved the problem by using:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
Instead of:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
For me, the error was being caused by a missing #SpringBootApplication annotation on the Spring class containing the main() method entry point which actually starts the Boot application. Using the following resolved the error:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Likely a corrupt download. Try removing ~/.m2/repository.
You actually just need to change webEnvironment = WebEnvironment.RANDOM_PORT to webEnvironment = WebEnvironment.MOCK in your #SpringBootTest annotation.
#vdou's answer helped me to resolve my issue.
In addition to adding #EnableAutoConfiguration, I also had to manually add the spring application type:
spring:
main:
web-application-type: reactive
There is obviously something in my dependencies that is causing Spring not to be able to discover the type.
I hope this helps somebody...
If you are using Kotlin, check if in your Application class that contains the main method, doesnt have this:
runApplication<Application>{
webApplicationType = WebApplicationType.REACTIVE
}
Then change the "REACTIVE" to "SERVELET", will work like a charm.
If None of the above solutions work, try adding
#ContextConfiguration(loader = AnnotationConfigContextLoader.class)
It may help you
import org.springframework.test.context.support.AnnotationConfigContextLoader;
Yet another reason this can occur is if you're importing in a configuration class for your test that is not marked with #TestConfiguration annotation

intellij junit #RunWith not resolved

I have the following test code:
package soundSystem;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class )
#ContextConfiguration(classes = CDPlayerConfig.class)
public class SonyCDPlayerTest {
#Autowired
private ICompactDisk cd;
#Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
}
}
This is a maven project, the problem is the exact same code would run in eclipse, but not in intellij.
I just can't find a way to resolve #RunWith
The #RunWith annotation has been replaced with #ExtendWith in JUnit 5.0 and above (which the latest spring version is now using).
Example:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = { SpringTestConfiguration.class })
public class GreetingsSpringTest {
// ...
}
Quoted from Baeldung:
Note that SpringExtension.class is provided by Spring 5 and integrates
the Spring TestContext Framework into JUnit 5.
Ref: https://www.baeldung.com/junit-5-runwith
Simple: your IDE is not configured to for unit testing.
In other words: you are missing all the JUnit related classes. You can see that all those JUnit imports are underlined; as IntelliJ simply doesn't know about the JARs that contain the corresponding classes.
See here on how to fix that.

Categories