Our Spring Boot REST API currently has a pretty large unit test repository. The unit tests refactor common reusable test code out into TestUtil
classes which are @Component
annotated.
It appears that the SpringRunner
unit test cases can only find the @Autowired TestUtil
classes if they are imported as part of the class parameter of the @SpringBootTest
annotation.
Additionally, all @Autowired
variables inside the TestUtil
classes also need to be imported in the classes parameter of the @SpringBootTest
annotation.
Since we have about 30 unit test case classes and each class needs to import roughly 40 other classes in the @SpringBootTest
annotation, one can imagine how unmaintainable this has become.
If a class is not imported as part of the @SpringBootTest
classes parameter, the following error is thrown
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.company.FeeTest': Unsatisfied dependency expressed through field 'accountTestUtils'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.company.accountTestUtils' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Does anybody know of a better way to use @Autowired
annotation inside Unit Test Cases without having to explicitly import them inside the @SpringBootTest
annotation?
A code example is below
FeeTest.java
package com.company;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
AccountTestUtils.class,
... need to list any @Autowired component in AccountTestUtils
})
public class FeeTest {
@Autowired
private AccountTestUtils accountTestUtils;
@Test
public void basicFeeTestExpectSuccess() {
accountTestUtils.createAccount();
...
}
}
TransferTest.java
package com.company;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
AccountTestUtils.class,
... need to list any @Autowired component in AccountTestUtils
})
public class TransferTest {
@Autowired
private AccountTestUtils accountTestUtils;
@Test
public void basicTransferTestExpectSuccess() {
accountTestUtils.createAccount();
...
}
}
AccountTestUtils.java
package com.company;
@Component
public class AccountTestUtils {
@Autowired
private IService1 someService1;
@Autowired
private IService2 someService2;
@Autowired
private SomeRepository someRepository1;
public void createAccount() {
someService1.doSomething();
someService2.doSomething();
someRepository2.doSomething();
}
}
Our package structure is the common maven structure
/src
/main
/java
/resources
/test
/java
/resources