I write the test for the Spring Boot and have 2 classes that are testing the API and the repository. The skeletons are provided below,
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
#AutoConfigureMockMvc
public class AppointmentAPITest {
/*
* we need a system to simulate this behavior without starting a
* full HTTP server. MockMvc is the Spring class that does that.
* */
#Autowired
private MockMvc mockMvc;
#MockBean
private AppointmentAPI api;
// now the tests are going on
}
The repository test class,
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class AppointmentRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private AppointmentRepository repository;
// write the test here
}
How do I use a single class to run them all? For example, if the class will be AppointmentApplicationTests,
#RunWith(SpringRunner.class)
#SpringBootTest
public class AppointmentApplicationTests {
#Test
public void contextLoads() {
}
}
What will be the best way to configure this class so it calls all the tests in the API and repo classes?
I think simpliest way would be to create a Suite to have a collection of tests to be run, like:
JUnit 4
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({
some.package.AppointmentRepositoryTest,
some.package.AppointmentApplicationTests
})
public class MySuite {
}
Junit5
#RunWith(JUnitPlatform.class)
#SelectClasses({some.package.AppointmentRepositoryTest,
some.package.AppointmentAPITest.class})
public class JUnit5TestSuiteExample {
}
However this is not alwasy the best way to do it. Consider also to get acquainted with howto create test profile for maven toe perform a bunch of tests or packages.
Related
I am using MockitoJUnit library to test my controller. there are some variables which are declared as:
#Value("${mine.port}")
private Integer port;
when I run my test, it could not find the value mine.port in the resource folder as properties file. My controller is no problem to run, but the port number is null when I run my contoller junit test.
I used below annotation on my class:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(classes = myControl.class)
#WebAppConfiguration
#AutoConfigureMockMvc
I used below method in my junit test
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.build();
}
#Test
public void getName() throws Exception {
MockHttpServletRequestBuilder request =
MockMvcRequestBuilders.get("/service")
.contentType(MediaType.APPLICATION_JSON_VALUE);
MvcResult result = mockMvc.perform(request)
.andExpect(status().isOk()).andReturn(); }
I am confused, does anyone know if I am missing some settings? thx!
No one of the specified annotations will start a Spring container :
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(classes = myControl.class)
#WebAppConfiguration
#AutoConfigureMockMvc
To write a test slice focused on the controller don't use a Mockito runner : #RunWith(MockitoJUnitRunner.class) otherwise you could not start a Spring container. MockitoJUnitRunner is for unit tests, not integration tests.
To know when and how to write unit and integration tests with Spring Boot you could read this question.
Instead of, use the #WebMvcTest annotation with a Spring runner such as :
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#WebMvcTest
public class WebLayerTest {
...
}
You can rely on this Spring guide to have more details.
I am new to JUnit and automated testing and really want to get into automating my tests. This is a Spring Boot application. I have used Java Based Annotation style instead of XML based configuration.
I have a test class in which I'd like to test a method which retrieves a response based on a users' input.
Testing class:
#RunWith(SpringRunner.class)
#SpringBootTest
public class SampleTest(){
#Autowired
private SampleClass sampleClass;
#Test
public void testInput(){
String sampleInput = "hi";
String actualResponse = sampleClass.retrieveResponse(sampleInput);
assertEquals("You typed hi", actualResponse);
}
}
Inside my "SampleClass" I have autowired a bean like this.
#Autowired
private OtherSampleClass sampleBean;
Inside my "OtherSampleClass" I have annotated a method like so:
#Bean(name = "sampleBean")
public void someMethod(){
....
}
The issue I'm having is when I try to run the test without the #RunWith and #SpringBootTest annotations when I try to run the test my variables annotated #Autowired are null. And when I try to run the test with those annotations RunWith & SpringBootTest then I get an
IllegalStateException caused by BeanCreationException: Error creating
bean with name "sampleBean" AND failure to load application context
caused by BeanInstantiationException.
The code works 'properly' when I try to use it as a user would so I can always test this way but I think automated tests would be good for the longevity of the program.
I have used the Spring Boot Testing Docs to assist me in this.
The following config works for me.
File: build.gradle
testCompile("junit:junit:4.12")
testCompile("org.springframework.boot:spring-boot-starter-test")
File: MYServiceTest.java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
#SpringBootTest(classes = Application.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
public class MYServiceTest {
#Autowired
private MYService myService;
#Test
public void test_method() {
myService.run();
}
}
It's best to keep Spring out of your unit tests as much as possible. Instead of Autowiring your bean just create them as a regular object
OtherSampleClass otherSampleClass = mock(OtherSampleClass.class);
SampleClass sampleClass = new SampleClass(otherSampleClass);
But for this you need to use the Constructor injection instead of Field Injection which improves testability.
Replace this
#Autowired
private OtherSampleClass sampleBean;
With this
private OtherSampleClass sampleBean;
#Autowired
public SampleClass(OtherSampleClass sampleBean){
this.sampleBean = sampleBean;
}
Take a look at this answer for an other code example
No need to inject (#Autowired private SampleClass sampleClass;) your actual class which you are testing, and remove SpringBootTest annotation, SpringBootTest annotation used for integration test cases.
find the following code will help you.
#RunWith(SpringRunner.class)
public class SampleTest(){
private SampleClass sampleClass;
I'm testing a REST controller using JUnit 4 and MockMvc. When I've written the test a few weeks ago, everything worked as expected. I've done some modifications in my code but I didn't change the JUnit test. Now, when I'm trying to run my tests, I have the error:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/application.properties]
Here is my code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyServerApplication.class)
#SpringBootTest
#Transactional
public class MovieControllerTest {
private MockMvc mockMvc;
#Autowired
private MovieRepository movieRepository;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// Some tests
}
And my main class:
#SpringBootApplication
public class MyServerApplication{
public static void main(String[] args) {
SpringApplication.run(MyServerApplication.class, args);
}
}
My application.properties file is located in src/main/resources. I didn't move this file, I didn't do anything but add some code in my services and add some properties in my file.
I read SO questions & doc, and tried these solutions:
Check that src/main/resources is still in my test classpath
Add #PropertySource("classpath:application.properties") under the annotations in my test ; it didn't work so I tried to create a src/test/resources with a copy of application.properties inside, as suggested in one post
Add #PropertySource("classpath:application.properties") in the main class instead of the test class
Add #WebAppConfiguration annotation
Add #WebMvcTest annotation
I didn't try all of these solutions at the same time of course, I removed the added code after each failure.
I can still run my code without any issue though, only the test class results in FileNotFoundException.
How to solve this? And why do I have an issue with the test class but everything working fine when I run my server?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyServerApplication.class)
#SpringBootTest
#Transactional
public class MovieControllerTest { ... }
This is what you have on your test class. When using #SpringBootTest you shouldn't be using #ContextConfiguration (see testing chapter of the Spring Boot Reference Guide).
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#Transactional
public class MovieControllerTest { ... }
I would also suggest you use Spring Boot for testing instead of trying to do things manually. For mock mvc testing Spring Boot applications there are special slices and setup already done for you.
To enable this add #AutoConfigureMockMvc to your test and put #Autowired on the MockMvc field (and remove the setup in your #Before method).
I'm developing an application which uses AspectJ with Java. In development, I use ajc and java together. AspectJ calls some code segments when necessary and I want to test these code segments called by AspectJ. I tried to do it with Mockito but I failed, does anyone know any other way to test it?
I am not sure on how to do it in plain Java and JUnit, but if you have access to Spring-Integration-Test you can have an easy approach with the MockMVC and support classes that it offers.
And bellow you can see an example in which I am testing a controller that has an Aspect wrapped around it:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
public class ControllerWithAspectTest {
#Autowired
private WebApplicationContext wac;
#Autowired
private MockMvc mockMvc;
#Autowired
#InjectMocks
private MongoController mongoController;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
// if you want to inject mocks into your controller
MockitoAnnotations.initMocks(this);
}
#Test
public void testControllerWithAspect() throws Exception {
MvcResult result = mockMvc
.perform(
MockMvcRequestBuilders.get("/my/get/url")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
}
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
static class Config extends WebMvcConfigurerAdapter {
#Bean
public MongoAuditingAspect getAuditingAspect() {
return new MongoAuditingAspect();
}
}
}
You can use the approach above even if you don't have Spring configured in your application, as the approach I've used will allow you to have a configuration class (can and should be a public class residing in it's own file).
And if the #Configuration class is annotated with #EnableAspectJAutoProxy(proxyTargetClass = true), Spring will know that it needs to enable aspects in your test/application.
If you need any extra clarification I will provide it with further edits.
EDIT:
The Maven Spring-Test dependency is:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
I just created a JUnit4 Runner to allow AspectJ Load Time Weaving on JUnit test cases. Here is a simple example:
I created a HelloService to return a greeting. And I created an Aspect to make names in the greeting upper case. Finally i created a unit test to use the HelloService with a lower case name and expect an upper case result.
All the details of the example are part of the GitHub project for reference:
https://github.com/david-888/aspectj-junit-runner
Just include the most up to date aspectj-junit-runner JAR in your classpath. Then your tests may look like this:
#AspectJConfig(classpathAdditions = "src/test/hello-resources")
#RunWith(AspectJUnit4Runner.class)
public class HelloTest {
#Test
public void getLiveGreeting() {
String expected = "Hello FRIEND!";
HelloService helloService = new HelloService();
String greeting = helloService.sayHello("friend");
Assert.assertEquals(expected, greeting);
}
}
I'm trying to replace an #Autowired object with a Mockito mock object. The usual way of doing this was with xml using Springockito:
<mockito:mock id="SomeMock" class="com.package.MockInterface" />
Currently I'm trying to move over to using Spring's JavaConfig to do the job. All of a sudden the Java expressions are a whole lot more verbose than xml:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTestClass {
#Configuration
static class Config {
#Bean
public MockInterface somethingSpecial() {
return Mockito.mock(MockInterface.class);
}
}
#Autowired MockInterface mockObj;
// test code
}
I discovered a library called Springockito-annotations, which allows you to do the following:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=SpringockitoContextLoader.class)
public class MyTestClass {
#Autowired #ReplaceWithMock MockInterface mockObj;
// test code
}
Clearly, a whole lot prettier :) The only problem is that this context loader doesn't allow me to use #Configuration and JavaConfig for other beans (if I do, Spring complains that there are no candidates that match those autowired fields).
Do you guys know of a way to get Spring's JavaConfig and Springockito-annotations to play nice? Alternatively, is there another shorthand for creating mocks?
As a nice bonus, using Springockito and xml config, I was able to mock out concrete classes without providing autowiring candidates to its dependencies (if it had any). Is this not possible without xml?
Moving away from the now unmaintained (as of this writing) Spingockito-annotations and to Mockito, we have a way of doing this very simply:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration
public class MyTestClass {
#Mock MockInterface mockObj;
// test code
}
If you're using a real object, but would like to mock a dependency within it, for instance testing a service layer with DAO:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration
public class MyTestClass {
#InjectMocks RealService;
#Mock MockDAO mockDAO;
// test code
}
Finally, this can also be applied to Spring-boot, but using annotation initialization within setUp() until multiple class runners are supported:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyMainSpringBootClass.class)
public class MyTestClass {
#InjectMocks RealService;
#Mock MockDAO mockDAO;
#Before
public final void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
}
// test code
}
Outdated and deprecated!
Read about mocking and spying in Spring Boot 1.4
Please read also #ethesx answer,
Springockito is unmaintaned
Old answer
This is possible now to mock Spring application without any XML file with Springockito-annotations.. This solution works also with Spring Boot.
import static org.mockito.BDDMockito.*;
import org.kubek2k.springockito.annotations.*;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class,
loader = SpringockitoAnnotatedContextLoader.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MainControllerTest {
#Autowired
MainController mainController;
#Autowired
#ReplaceWithMock
FooService fooService;
#Test
public void shouldGetBar() {
//given
given(fooService.result("foo")).willReturn("bar");
//when
Bar bar build = fooService.getBar("foo");
//then
assertThat(bar).isNotNull();
}
}
Dependencies: org.kubek2k:springockito-annotations:1.0.9
It appears that SpringockitoContextLoader extends GenericXmlContextLoader which is described as:
Concrete implementation of AbstractGenericContextLoader that reads bean definitions from XML resources.
So you are limited to xml bean definitions at the moment.
You could write your own context loader, taking relevant parts from the SpringockitoContextLoader class. Take a look here to get started, perhaps you could extend AnnotationConfigContextLoader for example?