I want to test the repository layer and I'm using spring webflux. My test class is as follows
#RunWith(SpringRunner.class)
#DataJpaTest
public class DataTester {
#Autowired
private MyRepository repository;
#Test
.....
}
Even though this would work in spring-mvc when using spring-weblux I get the following error.
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.context.ApplicationContextException: Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean.
How to resolve this? If I am to start the whole application context with #SpringBootApplication it works. Any other options without using that?
The reason for this was that in the application.properties the application type was set as reactive.
spring.main.web-application-type=reactive
This tries to auto configure a web server in this case a reactive web server. As #DataJpaTest does not provide a bean for that, this fails. This can be fixed in either two ways.
One is by Adding an application.properties file in the resources directory of the test package and setting the value as,sprig.main-web-application-type=none solves this issue.
Or we can simple pass a property value to the annotation as follows. #DataJpaTest(properties = "spring.main.web-application-type=none")
If you are using Spring Boot 2+ then only #DataJpaTest is enough on test class.
So your test class should be
#DataJpaTest
public class DataTester {
#Autowired
private MyRepository repository;
#Test
.....
}
Related
I am testing a line in my code that is supposed to cause a failure when loading a Spring Boot application context. However, using #SpringBootTest will not help in this situation because there will be an (expected) failure in the application initialization, and the test method will never be reached.
#SpringBootTest
class SomeTestClass {
#Autowired
ApplicationContext applicationContext
#Test
void someTestCase() {
//some assert about application context
}
}
Is there any way to configure a #SpringBootTest that will survive a failure on the class level? Alternatively, is there any way to manually run a mini Spring Boot Application of just the affected components?
If I understood your problem correctly, you should use SpringRunner.
The SpringRunner provides support for loading a Spring ApplicationContext and having beans #Autowired into your test instance. It actually does a whole lot more than that (covered in the Spring Reference Manual), but that's the basic idea.
So you can add it like that :
#RunWith(SpringRunner.class)
#SpringBootTest
class SomeTestClass {
#Autowired
ApplicationContext applicationContext
#Test
void someTestCase() {
//some assert about application context
}
}
Here's kind of what I have:
#RunWith(SpringRunner::class)
#ActiveProfiles("unit-test")
#WithUserDetails
#WebMvcTest(MyController::class)
class MyControllerTest {
#MockBean
lateinit var service: MyService
#Autowired
lateinit var mvc: MockMvc
But I keep getting exceptions similar to:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
and every time I add in a dependency, such as by:
#MockBean
lateinit var anotherBean: AnotherBean
another missing bean is thrown (kind of endless).
Is there a proper solution for this in Kotlin?
Just add annotation #SpringBootTest, from the spring guides:
The #SpringBootTest annotation tells Spring Boot to go and look for a main configuration class (one with #SpringBootApplication for instance), and use that to start a Spring application context. You can run this test in your IDE or on the command line (mvn test or gradle test) and it should pass.
Annotate your test class with just following two annotations
#WebMvcTest(secure = false)
#ContextConfiguration(classes = [YourClass::class])
secure = false is to disable the Spring security configuration.
I am using test annotation introduced in spring-boot 1.4.3 for my integration tests
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyServiceIT { }
According to documentation, test context is cached and reused to speed up integration tests. This behavior is what I want since it takes significant amount of time to initialize application context. My failsafe plugin is configured with
<forkCount>1</forkCount>
<reuseForks>true</reuseForks>
to allow integration tests to run in the same process to take advantage of application context caching.
Recently, I wrote a integration test used #MockBean annotation to mock behavior for some beans.
#RunWith(SpringRunner.class)
#SpringBootTest
public class AnotherServiceIT {
#MockBean
SomeService service1
}
While the test runs fine on it's own, when running through maven verify, multiple integration tests fails with the error message
javax.naming.NamingException: Another resource already exists with
name dataSource - pick a different name
If I skip this particular test with JUnit #Ignore annotation, everything goes back to normal.
This behavior seems to indicate that using #MockBean changes the caching behavior, and each test attempts to create its own datasource. I should also mention that I am using an AtomikosDataSourceBean created through XADataSourceAutoConfiguration.
How can I overcome this issue so my integration test can still use cached context and use #MockBean at the same time?
Hmm, does SomeService relate to your Datasource in any way?
Because your context is cached and #MockBean does the following:
used to add mocks to a Spring ApplicationContext ... Any existing single bean of the same type defined in the context will be replaced by the mock,
and
If there is more than one bean of the requested type, qualifier metadata must be specified at field level:
#RunWith(SpringRunner.class)
public class ExampleTests {
#MockBean
#Qualifier("example")
private ExampleService service;
Edit:
So if your SomeService is an implementation of a DataSource try adding a Qualifier. If SomeService has a DataSource in it, and you need to access some methods in it, you could try to use #Mock and specify the any objects that need to be returned either through their own mock or autowire.
#Mock
SomeService someService;
#Mock
SomeDependency mockDependency;
#Autowired
OtherDependency realDependency;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
doReturn(mockDependency).when(someService).getSomeDependency();
doReturn(realDependency).when(someService).getOtherDependency();
}
I'm not able to run a simple test in spring boot 1.4. I followed the tutorial from the official site testing-the-spring-mvc-slice but I didn't get it to work.
every time i get the following error:
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
any ideas, hints?
Thanks in advance
Edit:
this is the controller
#Controller
public class UserManagementController {
#GetMapping(value = "/gs/users/getUsers")
public #ResponseBody String getAllUsers() {
return "test";
}
}
this is the test
#RunWith(SpringRunner.class)
#WebMvcTest(UserManagementController.class)
public class UserManagementControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void showUserView() throws Exception {
this.mvc.perform(get("/gs/users/getUsers"))
.andExpect(status().isOk())
.andDo(print());
}
}
From my point of view it's exactly the same like this post from the site.
the #WebMvcTest will do:
Auto-configure Spring MVC, Jackson, Gson, Message converters etc.
Load relevant components (#Controller, #RestController, #JsonComponent etc)
Configure MockMVC
now why i need to configure a "super" class
The search algorithm works up from the package that contains the test
until it finds a #SpringBootApplication or #SpringBootConfiguration
annotated class. As long as you’ve structure your code in a sensible
way your main configuration is usually found.
So you have annotated your test with #*Test. It run, checked for configuration in subclasses, haven't found any, thrown an exception.
You have to have a config in a package or subpackage of test class or directly pass config class to #ContextConfiguration or #SpringBootTest or have class annotated with #SpringBootApplication.
According to #SpringBootApplication. I have tested controller in way you have mentioned with #WebMvcTest: it works if application has class annotated as #SpringBootApplication and fails with exception you've mentioned if not. There is remark it the article you mentioned:
In this example, we’ve omitted classes which means that the test will
first attempt to load #Configuration from any inner-classes, and if
that fails, it will search for your primary #SpringBootApplication
class.
Github discussion about the same point.
Spring Boot Documentation
I have a Spring App that uses JPA repositories (CrudRepository interfaces). When I try to test my controller using the new Spring test syntax #WebMvcTest(MyController.class), it fails coz it tries to instantiate one of my service class that uses JPA Repository, does anyone has any clues on how to fix that? The app works when I run it.
Here is the error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.myapp.service.UserServiceImpl required a bean of type 'com.myapp.repository.UserRepository' that could not be found.
Action:
Consider defining a bean of type 'com.myapp.repository.UserRepository' in your configuration.
According to the doc
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. #Controller, #ControllerAdvice, #JsonComponent Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not #Component, #Service or #Repository beans).
This annotion only apply on the Spring MVC components.
If you are looking to load your full application configuration and use MockMVC, you should consider #SpringBootTest combined with #AutoConfigureMockMvc rather than this annotation.
I was able to unit test a Rest Controller by implementing junit 5 and using #SpringJUnitConfig along with #WebMvcTest. I am using Spring Boot 2.4.5 and this is my example:
#SpringJUnitConfig
#WebMvcTest(controllers = OrderController.class)
class OrderControllerTest {
#Autowired
private MockMvc mockMvc;
// This is a Mock bean of a Spring Feign client that calls an external Rest Api
#MockBean
private LoginServiceClient loginServiceClient;
// This is a Mock for a class which has several Spring Jpa repositories classes as dependencies
#MockBean
private OrderService orderService;
#DisplayName("should create an order")
#Test
void createOrder() throws Exception {
OrderEntity createdOrder = new OrderEntity("123")
when(orderService.createOrder(any(Order.class))).thenReturn(createdOrder);
mockMvc.perform(post("/api/v1/orders").contentType(MediaType.APPLICATION_JSON).content("{orderId:123}"))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))TODO: here it will go the correlationId
.andExpect(jsonPath("$.orderId").value("123"));
}
}
Please only use #SpringBootTest when you are implementing integration tests.
I faced this same problem. Using #SpringBootTest and #AutoConfigureMockMvc worked perfectly for me.