I have a service class which uses a dependency -
MyService
@Service
@ToString
public class MyService{
Dependency dependency;
public MyService(Dependency dependency) {
System.out.println("started MyService constructor");
this.dependency = dependency;
System.out.println("ended MyService constructor with dependency = " + this.dependency);
}
public void myMethod() {
System.out.println("printing in myMethod : " + dependency.someMethod());
}
public void setDependency(Dependency dependency) {
this.dependency = dependency;
System.out.println("called setter with dependency = " + this.dependency);
}
}
Dependency
@Component
public class Dependency {
public String someMethod() {
return "calling dependency someMethod";
}
}
I wrote 2 test cases for MyService class -
@SpringBootTest
@ContextConfiguration(classes = {MyService.class})
class MyServiceTest {
@InjectMocks
MyService myService;
@MockBean
Dependency dependency;
@Value("${someproperty}")
private String someProperty;
@BeforeEach
void beforeEach() {
System.out.println("beforeEach");
}
@Test
void test1() {
System.out.println("test1 start");
when(dependency.someMethod()).thenReturn("calling mock dependency 1 someMethod");
myService.myMethod();
System.out.println("test1 end");
}
@Test
void test2() {
System.out.println("test2 start");
when(dependency.someMethod()).thenReturn("calling mock dependency 2 someMethod");
myService.myMethod();
System.out.println("test2 end");
}
}
I tried making MyService and Dependency static/non static in MyServiceTest and got following results -
- MyService static, Dependency static
Constructor for MyService runs with dependency = null
first test runs and fails
setDependency is called and dependency is set to a mock object
second test runs fine - MyService static, Dependency non static
Constructor for MyService runs with dependency = null
first test runs and fails
second test runs and fails - MyService non static, Dependency static
Constructor for MyService runs with dependency = null
first test runs and fails
Constructor for MyService runs with dependency = some mock object
second test runs fine - MyService non static, Dependency non static
Constructor for MyService runs with dependency = null
first test runs and fails
Constructor for MyService runs with dependency = null
second test runs fine
Can someone please help me understand these behaviors.
JUnit creates a new instance of the test class for every single test method that is executed. You must not use static fields, otherwise tests will not be isolated anymore. AFAIK the order of execution is not guaranteed to be deterministic.
@MockBeanis a Spring Boot annotation and@InjectMocksis a Mockito annotation. Running your test withSpringExtensionwill not process any Mockito extensions.You shouldn't mix Spring Boot and Mockito annotations, as that almost always doesn't do what you expect.
@InjectMockswill only inject@Spyand@Mockinstances (via Reflection)@MockBeanwill create a mocked bean instance and adds it to the application context. These beans will be picked up when processing@Autowiredfields and constructors.Either way, both Spring Boot and Mockito annotations can only handle (only support) and inject non-static fields.
So you need to decide if you want to write a Spring Boot test or a Mockito-based test:
Mockito-based test
This doesn't use the Spring application context at all and creates and injects all instances manually.
Spring Boot test
This requires the Spring application context to be set up and uses it to look up and wire dependencies.