I have a collection of Junit test classes with an autowired element (Spring). If I execute each Junit test class separately, everything works ok.
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class TestClass {
#Autowired
MyController control;
#Test
public void geolocTest() throws Exception {
...
}
I want to create a "Test Suite", but if I execute the Test Suite, it looks like the autowired elements are "null", so every test fails.
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestClass.class
})
public class TestSuit extends TestCase {
...
}
What can I do? Thanks
NOTE:
What I want is to execute a code before all test classes, and another code after all test classes. I think I need a Suite for this...
As mentioned, you should use:
#RunWith(SpringJUnit4ClassRunner.class)
You can use #Before, #After, #BeforeClass, #AfterClass.
First two will be executed before and after each test case in a given Test class.
Last two will be executed only once per given Test class.
Your tests should be atomic as much as possible, so if you have all Test cases mutually dependent on same data or order of execution, try to rewrite this first.
If you wish to share some application properties, the good thing, for auto wiring between all test cases, such as the urls to mocks, take a look at the Spring profiles.
You can then have production specific and test specific properties which will be injected based on the current profile.
Take a look at the example and official docs:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
http://www.mkyong.com/spring/spring-profiles-example/
#Configuration
#ComponentScan
#Profile("test")
#PropertySource(value = "classpath:/yourApp.properties")
public class TestConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
You can then injected shared properties from the file in your test classes like this:
#Value("${mock.url}")
private String mockUrl;
Your missing at least the following
#RunWith(SpringJUnit4ClassRunner.class)
on your TestClass.
Related
This question is a sequel to Can I use code to control the dependency resolution decisions made by ApplicationContext in Spring Boot?
The accepted answer is to define a nested class within each #SpringBootTest test fixture class, to annotate it with #TestConfiguration and to define within it a factory method for each bean that needs to be resolved. The influence of the nested classes is scoped to the test fixture affecting all of the tests in the fixture but not affecting tests defined in other fixtures.
This provides fine grained control over the dependencies injected into the components when running the tests in each test fixture.
The problem with this approach is that it requires adding a nested resolver class within each test fixture class.
This is not scalable.
Consider a project with 10 test fixtures. 9 of these use the same injected dependencies and only the 10th requires a different implementation for only one particular interface.
In this case I would need to copy the test configuration class into 9 test fixture classes and use a second configuration class for only the 10th test.
I need a more scalable way to do this. For instance, in the case above, I would like to be able to define two configuration classes, one for each of the two configurations used by the test fixtures. Then I would like to be able specify for each test fixture which of the two configuration classes should be used.
I have tried:
I tried importing the nested configuration class of one text
fixture into another test fixture using the #Import annotation into
the latter, but when doing so, the configuration class is ignored in
the latter.
I also tried moving a nested configuration class to the
upper level so that it might be used for all test fixtures that do
not explicitly define a different one as a nested class, but in this
case the configuration class is ignored by all test fixtures.
So in summary I am looking for an efficient way that would allow me to write each configuration class only once and then to selectively apply one to each SpringBootTest class without needing to copy it.
After some experimentation I have reached the following solution.
I will add all the details summarizing what I learned in the previous question too.
Background
We have two interfaces: IClient and IServer
There are two implementations of IClient: RealClient and MockClient.
There are two implementations of IServer: RealServer and MockServer.
Requirements
Production code (in main/java) should use the Real implementations of both.
Test Fixtures (annotated with #SpringBootTest in test/java)
InterfaceTests defines tests that should use a MockServer and a MockClient
ClientTests defines tests that should use a MockServer and RealClient to test the RealClient.
ServerTests defines tests that should use a MockClient and a RealServer to test the RealServer.
IntegrationTests defines tests that should use a RealServer and a RealClient
From the above it is clear that there are four combinations of mock/real client/server and each combination is needed in some area of the code.
Solution
This solution makes use of the #Configuration and #TestConfiguration annotations in order to implement these requirements with no code duplication.
Do NOT annotate interfaces nor their implementations with #Component
Under main/java implement a configuration class as follows:
#Configuration
public class RealInjector {
#Bean
public IServer createServer(){
return new RealServer();
}
#Bean
public IClient createClient(){
return new RealClient();
}
}
Under test/java implement these three test configuration classes
#TestConfiguration
public class AllMockInjector {
#Bean
public IServer createServer(){
return new MockServer();
}
#Bean
public IClient createClient(){
return new MockClient();
}
}
#TestConfiguration
public class MockServerInjector{
#Bean
public IServer createServer(){
return new MockServer();
}
#Bean
public IClient createClient(){
return new RealClient();
}
}
#TestConfiguration
public class MockClientInjector{
#Bean
public IServer createServer(){
return new RealServer();
}
#Bean
public IClient createClient(){
return new MockClient();
}
}
Annotate the InterfaceTests test fixture as follows:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {AllMockInjector.class})
public class InterfaceTests { ... }
Annotate the ClientTests test fixture as follows:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {MockServerInjector.class})
public class ClientTests { ... }
Annotate the ServerTests test fixture as follows:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {MockClientInjector.class})
public class ServerTests { ... }
Annotate the IntegrationTests test fixture as follows:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {RealInjector.class})
public class IntegrationTests { ... }
Finally
In order for the test configuration classes to override the RealInjector configuration class from main/java we need to set the property:
spring.main.allow-bean-definition-overriding=true
One way to do this is to annotate each of the above test fixtures as follows:
#SpringBootTest(properties = ["spring.main.allow-bean-definition-overriding=true"])
class TestFixture { ... }
but this is quite verbose especially if you have many test fixtures.
Instead you can add the following in the application.properties file under test/resources:
spring.main.allow-bean-definition-overriding=true
You may also need to add it in application.properties under main/resources too.
Summary
This solution gives you fine grained control over the implementations that are injected into your code for production and for tests. The solution requires no code duplication or external configuration files (apart from one property in test/resources/application.properties).
I have a requiremenmt where I need to mock a particular Spring bean, but during the JUnit execution the actual bean is being is also instantiated.
For example:
#Configuration
public class Config{
#Bean
public Foo fooBean(){
return new Foo();
}
}
Here is my code to Mock the Foo spring bean, so that during the JUnit execution, only the mocked Foo bean be created.
#Configuration
public class MockFooBean{
#Bean
#Primary
public Foo mockedBean(){
Mockito.mock(Foo.class)
}
}
The requirement is during the JUnit execution I want to have mockedBean() to be called (Which is happening right now), BUT I do not want fooBean() to be called again, for the Foo bean creation.
Edited Recently:
Still no luck. I tried below:
#Configuration
public class MockFooBean{
#Bean
#Primary
public Foo mockedBean(){
Mockito.mock(Foo.class)
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=MockFooBean.class, loader=AnnotationConfigurationContextLoader.class)
public class TestClass{
#Autowired
private ClassUnderTest classUnderTest;
//JUNITS//
}
I terribly miss the good old days where we have good control over the code. Any help?
Actually you should have separate configuration for tests. separate beans for tests so they will not be loaded while running tests.
you can go through below link
https://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles
Because #TestConfiguration is an addition to the current configuration(s). It is not executed instead of the current configuration(s) but it adds and replaces (if already defined) beans that it specifies.
So the current configuration(s) is first loaded and the TestConfiguration is then loaded.
From the documentation :
If you want to customize the primary configuration, you can use a
nested #TestConfiguration class. Unlike a nested #Configuration class,
which would be used instead of your application’s primary
configuration, a nested #TestConfiguration class is used in addition
to your application’s primary configuration.
To not allow Spring to instantiate the bean that you override, you have to exclude it from the context. To achieve that you could use :
specific configuration for tests
profiles
#ConditionalOnProperty .
For example with a specific configuration for tests :
#ExtendWith(SpringExtension.class)
#SpringBootTest // or a slicing test
#Import(MyTestsConfiguration.class)
public class FooTest {
//...
}
For example with profiles :
#Profile("prod")
#Configuration
public class Config{
#Bean
public Foo fooBean(){
return new Foo();
}
}
#Profile("test")
#Configuration
public class MockFooBean{
#Bean
#Primary
public Foo mockedBean(){
Mockito.mock(Foo.class)
}
}
And in the test, active the test profile :
#ExtendWith(SpringExtension.class)
#SpringBootTest // or a slicing test
#ActiveProfiles("test")
public class FooTest{
....
}
Let's say I'm testing a repository :
#RunWith(SpringRunner.class)
#SpringBootTest
public class UserRepositoryTest {
#Test
(...)
#Test
(...)
}
I'm ok that spring loads other repositories, but I'm not ok it loads the embedded Tomcat, the services, the controllers, ... every time I launch one of these JUnit.
What is the simplest way to achieve this?
I've tried to put some inner #Configuration class with a #ComponentScan limited to my repository package but it didn't work (it was just ignored).
Use the annotation #DataJpaTest instead of #SpringBootTest. It only loads the persistence related part of Spring.
#RunWith(SpringRunner.class)
#DataJpaTest
public class UserRepositoryTest {
#Test
(...)
#Test
(...)
}
You will find a detailed solution here
If you have some usage of JdbcTemplate then take a look to this answer
It looks like there is not one single answer to this question.
Of course, for JPA repositories, Lore answer is the best : use #DataJpaTest (or #JdbcTest for my use case). But be also sure to use "#AutoConfigureTestDatabase(replace = Replace.NONE)" if your test data is in your database and not in some in-memory one.
Also there is a special chapter talking about this in Spring doc :
Spring Boot’s auto-configuration system works well for applications
but can sometimes be a little too much for tests. It often helps to
load only the parts of the configuration that are required to test a
“slice” of your application.
source : https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests
But it doesn't show all you can/need to do.
For example, I had a smtpClientService to test.
To test this service, alone in its own layer, I had to do these specific adaptations (if I omit "#AutoConfigureWebClient", I won't get RestTemplateBuilder injected) :
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureWebClient
public class smtpClientServiceTest {
#Autowired
SmtpClientService service;
#Configuration
#Import(SmtpClientConfig.class)
#ComponentScan(basePackageClasses = SmtpClientService.class)
static class TestConfiguration {
}
#Test
public void testSendMessage() {
(...)
}
}
Base test class for integration testing imports base configuration with component scan that includes almost all packages. In one test class I want to override some beans with Mocs, but this inner configuration is scanned and overrides beans for all tests. Is there some way to avoid this?
I've found the way I like mocking beans with by essentially having a separate MockObjectsConfig class with the mock objects I want using the standard Spring Context Configuration, and then import it alongside my real test config. You can also annotate your mock bean with #Profile and test with #ActiveProfiles if you need to prevent a conflict there.
#Configuration
#Profile("!test")
public class MyRealConfigClass {
#Bean
public YetAnotherClass yetAnotherClass() {
return new YetAnotherClass();
}
}
#Configuration
#Profile("test")
public class MockObjectsConfig {
#Bean
public YetAnotherClass yetAnotherClass() {
Mockito.mock(YetAnotherClass.class); // and add any thenReturns, answers, etc. here
}
}
Then include it in your test like so:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { MyRealConfigClass.class, MockObjectsConfig.class)
#ActiveProfiles({"test"})
public class MyJunitTest {
#Autowired
private RestController restController;
}
Then your mock bean will be used and not the real one from the production config.
I have an application where I use Spring (annotations, not xml), and I need to load the beans in my unit tests. I have the AppConfig class from my code which I want to use, but with a different datasource (one I define in the test folder). This is because I want to use an in memory DB in my tests, and not the real DB.
Here's how I try to run the AppConfig class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {App.class, AppConfig.class})
public class DAOManagerTest {
//All code goes here
#AutoWired
UserDAO userDAO;
#Test
public void testGet() {
List<User> test = userDAO.selectAll();
for (User u: test) {
u.toString();
}
}
}
This doesn't entirely work, as it fails on creating a bean inside the UserDAO class. I guess I need some tutorial / guide on how to deal with spring in unit tests. Should I define new beans in my test folder, or is it possible to user the spring class from my code? Also, is it possible to define a seperate datasource for the tests?
Yes. For example, if you define some beans in DAOManagerTest, using #Primary if necessary, and add DAOManagerTest.class to #ContextConfiguration.
There are so many other ways of arranging it though, like using profiles or mocks, etc.