Reputation: 21384
I tried:
@RunWith(SpringJUnit4ClassRunner.class)
@EnableAutoConfiguration(exclude=CrshAutoConfiguration.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class LikeControllerTest {
However the CRaSSHD still starts up. While currently it doesn't harm the test, I'd like to disable unnecessary modules during unit testing to speed up and also avoid potential conflicts.
Upvotes: 94
Views: 204851
Reputation: 566
So to disable the auto-loading of all Beans for a Test, the test class can explicitly mention the dependencies required.
This can be done using ContextConfiguration
annotation.
eg,
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {EmployeeService.class})
public class EmployeeLeavesTest {
@Autowired
private EmployeeService employeeService;
}
In this eg, only EmployeeService
class will be available and other beans will not be loaded.
Upvotes: 0
Reputation: 788
I think that the best solution currently for springBoot 2.0 is using profiles
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
public class ExcludeAutoConfigIntegrationTest {
// ...
}
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
anyway in the following link give 6 different alternatives to solve this.
Upvotes: 0
Reputation: 8420
Top answers don't point to an even simpler and more flexible solution.
just place a
@TestPropertySource(properties=
{"spring.autoconfigure.exclude=comma.seperated.ClassNames,com.example.FooAutoConfiguration"})
@SpringBootTest
public class MySpringTest {...}
annotation above your test class. This means other tests aren't affected by the current test's special case. If there is a configuration affecting most of your tests, then consider using the spring profile instead as the current top answer suggests.
Thanks to @skirsch for encouraging me to upgrade this from a comment to an answer.
Upvotes: 60
Reputation: 1285
I have struggled with a similar issue for one day... My Scenario:
I have a SpringBoot application and I use applicationContext.xml in scr/main/resources
to configure all my Spring Beans.
For testing(integration testing) I use another applicationContext.xml in test/resources
and things worked as I have expected: Spring/SpringBoot would override applicationContext.xml from scr/main/resources
and would use the one for Testing which contained the beans configured for testing.
However, just for one UnitTest I wanted yet another customization for the applicationContext.xml used in Testing, just for this Test I wanted to used some mockito beans, so I could mock
and verify
, and here started my one day head-ache!
The problem is that Spring/SpringBoot doesn't not override the applicationContext.xml from scr/main/resources
ONLY IF the file from test/resources
HAS the SAME NAME.
I tried for hours to use something like:
@RunWith(SpringJUnit4ClassRunner.class)
@OverrideAutoConfiguration(enabled=true)
@ContextConfiguration({"classpath:applicationContext-test.xml"})
it did not work, Spring was first loading the beans from applicationContext.xml in scr/main/resources
My solution based on the answers here by @myroch and @Stuart:
Define the main configuration of the application:
@Configuration
@ImportResource({"classpath:applicationContext.xml"})
public class MainAppConfig {
}
this is used in the application
@SpringBootApplication
@Import(MainAppConfig.class)
public class SuppressionMain implements CommandLineRunner
Define a TestConfiguration for the Test where you want to exclude the main configuration
@ComponentScan( basePackages = "com.mypackage", excludeFilters = { @ComponentScan.Filter(type = ASSIGNABLE_TYPE, value = {MainAppConfig.class}) }) @EnableAutoConfiguration public class TestConfig { }
By doing this, for this Test, Spring will not load applicationContext.xml and will load only the custom configuration specific for this Test.
Upvotes: 1
Reputation: 1365
If the issue is that your SpringBootApplication/Configuration you are bringing in is component scanning the package your test configurations are in, you can actually remove the @Configuration annotation from the test configurations and you can still use them in the @SpringBootTest annotations. For example, if you have a class Application that is your main configuration and a class TestConfiguration that is a configuration for certain, but not all tests, you can set up your classes as follows:
@Import(Application.class) //or the specific configurations you want
//(Optional) Other Annotations that will not trigger an autowire
public class TestConfiguration {
//your custom test configuration
}
And then you can configure your tests in one of two ways:
With the regular configuration:
@SpringBootTest(classes = {Application.class}) //won't component scan your configuration because it doesn't have an autowire-able annotation
//Other annotations here
public class TestThatUsesNormalApplication {
//my test code
}
With the test custom test configuration:
@SpringBootTest(classes = {TestConfiguration.class}) //this still works!
//Other annotations here
public class TestThatUsesCustomTestConfiguration {
//my test code
}
Upvotes: 3
Reputation: 69
@SpringBootTest(classes = {Application.class}
, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
, properties="spring.autoconfigure.exclude=com.xx.xx.AutoConfiguration"
)
ref:https://github.com/spring-projects/spring-boot/issues/8579
Upvotes: 6
Reputation: 4217
If you're having this problem with Spring Boot 1.4.x and up, you might be able to use @OverrideAutoConfiguration(enabled=true)
to solve the problem.
Similar to what was asked/answered here https://stackoverflow.com/a/39253304/1410035
Upvotes: 0
Reputation: 3000
I had a similar use case where I wanted to test a Spring Boot configured repository in isolation (in my case without Spring Security autoconfiguration which was failing my test). @SpringApplicationConfiguration
uses SpringApplicationContextLoader
and that has a JavaDoc stating
Can be used to test non-web features (like a repository layer) or start an fully-configured embedded servlet container.
However, like yourself, I could not work out how you are meant to configure the test to only test the repository layer using the main configuration entry point i.e. using your approach of @SpringApplicationConfiguration(classes = Application.class)
.
My solution was to create a completely new application context exclusive for testing. So in src/test/java I have two files in a sub-package called repo
RepoIntegrationTest.java
TestRepoConfig.java
where RepoIntegrationTest.java
has
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestRepoConfig.class)
public class RepoIntegrationTest {
and TestRepoConfig.java
has
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class TestRepoConfig {
It got me out of trouble but it would be really useful if anyone from the Spring Boot team could provide an alternative recommended solution
Upvotes: 28
Reputation: 789
With the new @SpringBootTest
annotation, I took this answer and modified it to use profiles with a @SpringBootApplication
configuration class. The @Profile
annotation is necessary so that this class is only picked up during the specific integration tests that need this, as other test configurations do different component scanning.
Here is the configuration class:
@Profile("specific-profile")
@SpringBootApplication(scanBasePackages={"com.myco.package1", "com.myco.package2"})
public class SpecificTestConfig {
}
Then, the test class references this configuration class:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { SpecificTestConfig.class })
@ActiveProfiles({"specific-profile"})
public class MyTest {
}
Upvotes: 7
Reputation: 8172
Another simple way to exclude the auto configuration classes,
Add below similar configuration to your application.yml file,
---
spring:
profiles: test
autoconfigure.exclude: org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
Upvotes: 66
Reputation: 3336
I had a similar problem but I came to a different solution that may help others. I used Spring Profiles to separate out test and app configuration classes.
Create a TestConfig class with a specific profile and exclude any app configuration from component scan you wish here.
In your test class set the profile to match the TestConfig and include it using the @ContextConfiguration annotation.
For example:
configuration:
@Profile("test")
@Configuration
@EnableWebMvc
@ComponentScan(
basePackages="your.base.package",
excludeFilters = {
@Filter(type = ASSIGNABLE_TYPE,
value = {
ExcludedAppConfig1.class,
ExcludedAppConfig2.class
})
})
public class TestConfig { ...}
test:
@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@WebAppConfiguration
public class SomeTest{ ... }
Upvotes: 13
Reputation: 5140
I struggled with this as well and found a simple pattern to isolate the test context after a cursory read of the @ComponentScan docs.
/**
* Type-safe alternative to {@link #basePackages} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
("com.example.test")
.Example
IsolatedTest.java
package com.example.test;
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan(basePackageClasses = {TestDomain.class})
@SpringApplicationConfiguration(classes = IsolatedTest.Config.class)
public class IsolatedTest {
String expected = "Read the documentation on @ComponentScan";
String actual = "Too lazy when I can just search on Stack Overflow.";
@Test
public void testSomething() throws Exception {
assertEquals(expected, actual);
}
@ComponentScan(basePackageClasses = {TestDomain.class})
public static class Config {
public static void main(String[] args) {
SpringApplication.run(Config.class, args);
}
}
}
...
TestDomain.java
package com.example.test;
public interface TestDomain {
//noop marker
}
Upvotes: 0
Reputation: 163
got into same kind of problem, wasn't able to exclude main spring boot class during testing. Solved it using following approach.
Instead of using @SpringBootApplication, use all three annotations which it contains and assign the name to @Configuration
@Configuration("myApp")
@EnableAutoConfiguration
@ComponentScan
public class MyApp { .. }
In your test class define configuration with exactly same name:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
// ugly hack how to exclude main configuration
@Configuration("myApp")
@SpringApplicationConfiguration(classes = MyTest.class)
public class MyTest { ... }
This should help. Would be nice to have some better way in place how to disable auto scanning for configuration annotations...
Upvotes: 2
Reputation: 10649
I think that using the @EnableAutoConfiguration
annotation on a test class won't work if you are using @SpringApplicationConfiguration
to load your Application
class. The thing is that you already have a @EnableAutoConfiguration
annotation in the Application
class that does not exclude the CrshAutoConfiguration
.Spring
uses that annotation instead of the one on your test class to do the auto configuration of your beans.
I think that your best bet is to use a different application context for your tests and exclude the CrshAutoConfiguration
in that class.
I did some tests and it seems that @EnableAutoConfiguration
on the test class is completely ignore if you are using the @SpringApplicationConfiguration
annotation and the SpringJUnit4ClassRunner
.
Upvotes: 8