How to skip @PostConstruct when unit testing
The method SalesDataAggregate is running on startup because of the @PostConstruct annotation. If you want to keep it from running during tests you can create the class containing the post construct in your test folder and add the @primary annotation so it takes precedence over the class in your main project.
@Primary
public class ClassContainingPostConstruct{
}
How to disable @PostConstruct in Spring during Test
Since you are not testing FileListService
but a depending class, you can mock it for tests. Make a mock version in a separate test package which is scanned only by test context. Mark it with @Primary
annotation so it takes precedence over production version.
How to automatically disable a Spring bean when running a unit test?
A prettier way to handle this would be
@Service
public class BackgroundTaskService {
@PostConstruct
@Profile("!test")
public void startTask() {
// ...
}
}
or even
@PostConstruct
public void startTask() {
if(env.acceptsProfiles("!test")) { // env is @Autowired Environment
// start task
}
}
Only if the test profile is not active, the @PostConstruct
method is run. In a Spring environment you want to use the tools Spring gives you, so use a profile instead of some custom indicator.
Testing spring bean with post construct
If you want to write a unit test of A
, then don't use Spring. Instead, instantiate A
yourself and pass a stub/mock of B
(either by using constructor injection or ReflectionTestUtils
to set the private field).
For example:
@Service
public class A {
private final B b;
@Autowired
public A(B b) {
this.b = b;
}
@PostConstruct
public void setup() {
b.call(param);
}
}
-
public class Test {
@Test
public void test() throws Exception {
B b = mock(b);
A a = new A(b);
// write some tests for A
}
}
If you have to use Spring, because you want to write an integration test, use a different application context, where you replace B
with a stub/mock.
For example, assuming B
is instantiated in a Production
class like this:
@Configuration
public class Production {
@Bean
public B b() {
return new B();
}
}
Write another @Configuration
class for your tests:
@Configuration
public class Tests {
@Bean
public B b() {
// using Mockito is just an example
B b = Mockito.mock(B.class);
Mockito.when(b).thenReturn("smth");
return b;
}
}
Reference it in your test with the @SpringApplicationConfiguration
annotation:
@SpringApplicationConfiguration(classes = { Application.class, Tests.class })
How to defer calling @PostConstruct until jUnit has setup test context
You can always start the context programmatically for such use case. Be aware that you're in charge of the lifecycle of the context in this case. The following pseudo-code illustrates this:
@Test
public void yourTest() {
// setup your database
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("/org/foo/your-context.xml");
// Or new AnnotationConfigApplicationContext(YourConfig.class)
try {
YourBean bean = context.getBean("beanId");
// Assertions
} finally {
context.close();
}
}
You probably need Spring to initialize your database. You could for instance use the regular Spring test context support to initialize only the beans you require for the database setup and start another context programmatically to assert your service. If that context needs some services that were used for the database initialization, you can start a child context instead, something like
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration // for instance FooTest-context.xml
public class FooTest {
@Autowired
private ApplicationContext mainContext;
@Test
public void yourTest() {
// setup your database
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext();
context.setParent(mainContext);
context.setConfigLocation("/org/foo/your-context.xml");
context.refresh();
try {
YourBean bean = context.getBean("beanId");
// Assertions
} finally {
context.close();
}
}
}
If that's becoming a recurrent use case you can create a template method that start the container and invoke a callback interface. That way you can share the context lifecycle management at a central place.
How to exclude a Spring Boot Component from running in JUnit unit tests?
The @MockBean
annotation replaces a bean with another bean implemented by a Mockito mock. You're not going to stub any methods on the mock. You only care that the bean is replaced with a bean that does nothing. Inside your test class:
@SpringBootTest
class MyTest {
@MockBean
private DatabaseInitialization databaseInitialization;
Related Topics
Java Coding Converted to Pseudo Code
How to Return a HTML Page from a Restful Controller in Spring Boot
Jpa- Joining Two Tables in Non-Entity Class
Java 8 Convert Utc Time to Edt/Est So That Date Remains the Same
How to Configure Hikaricp in My Spring Boot App in My Application.Properties Files
Include Comma in a Field Value of CSV (Delimeter as Comma) in Java
@Autowired - No Qualifying Bean of Type Found for Dependency
Disable Quick Settings Tile in Android
In Java: How to Zip File from Byte[] Array
Could Not Extract Resultset in Hibernate
Why Am I Getting the Error "The Method Is Undefined for the Type"
Could Not Read Json: Can Not Deserialize Instance of Hello.Country[] Out of Start_Object Token
How to Sort Integer Digits in Ascending Order Without Strings or Arrays
Re-Prompt User After Invalid Input in Java
How to Subtract a Constant Value from All Elements of an Array