服务类FooServiceImpl
用 @Service 注释又名 @Component
这使它有资格进行 Autowiring 。为什么在单元测试期间没有选择和 Autowiring 这个类?
@Service
public class FooServiceImpl implements FooService {
@Override
public String reverse(String bar) {
return new StringBuilder(bar).reverse().toString();
}
}
@RunWith(SpringRunner.class)
//@SpringBootTest
public class FooServiceTest {
@Autowired
private FooService fooService;
@Test
public void reverseStringShouldReverseAnyString() {
String reverse = fooService.reverse("hello");
assertThat(reverse).isEqualTo("olleh");
}
}
测试未能加载应用程序上下文,
2018-02-08T10:58:42,385 INFO Neither @ContextConfiguration nor @ContextHierarchy found for test class [io.github.thenilesh.service.impl.FooServiceTest], using DelegatingSmartContextLoader
2018-02-08T10:58:42,393 INFO Could not detect default resource locations for test class [io.github.thenilesh.service.impl.FooServiceTest]: no resource found for suffixes {-context.xml}.
2018-02-08T10:58:42,394 INFO Could not detect default configuration classes for test class [io.github.thenilesh.service.impl.FooServiceTest]: FooServiceTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
2018-02-08T10:58:42,432 INFO Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, (...)org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
2018-02-08T10:58:42,448 INFO Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@f0ea28, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@16efaab,(...)org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@9604d9]
2018-02-08T10:58:42,521 INFO Refreshing org.springframework.context.support.GenericApplicationContext@173f9fc: startup date [Thu Feb 08 10:58:42 IST 2018]; root of context hierarchy
2018-02-08T10:58:42,606 INFO JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-02-08T10:58:42,666 ERROR Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@19aaa5] to prepare test instance [io.github.thenilesh.service.impl.FooServiceTest@57f43]
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'io.github.thenilesh.service.impl.FooServiceTest': Unsatisfied dependency expressed through field 'fooService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.github.thenilesh.service.FooService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
. . .
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:?]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.github.thenilesh.service.FooService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 28 more
2018-02-08T10:58:42,698 INFO Closing org.springframework.context.support.GenericApplicationContext@173f9fc: startup date [Thu Feb 08 10:58:42 IST 2018]; root of context hierarchy
Full stack trace
如果测试类用 @SpringBootTest 注释然后它创建整个应用程序上下文,包括数据库连接和许多不相关的 bean,这些 bean 显然不需要这个单元测试(它不会是单元测试!)。所期望的是,只有 bean 在
FooService
依赖应该被实例化,除了被模拟的,用 @MockBean
.
最佳答案
您应该使用 @SpringBootTest(classes=FooServiceImpl.class)
.
正如在 Annotation Type SpringBootTest 上提到的:
public abstract Class[] classes
The annotated classes to use for loading an ApplicationContext. Can also be specified using @ContextConfiguration(classes=...). If no explicit classes are defined the test will look for nested @Configuration classes, before falling back to a SpringBootConfiguration search.
Returns: the annotated classes used to load the application context See Also: ContextConfiguration.classes()
Default: {}
这将只加载必要的类。如果不指定,它可能会加载数据库配置和其他会使您的测试变慢的东西。
另一方面,如果你真的想要单元测试,你可以在没有 Spring 的情况下测试这段代码 - 然后
@RunWith(SpringRunner.class)
和 @SpringBootTest
注释不是必需的。您可以测试 FooServiceImpl
实例。如果您有 Autowired
/injected 属性或服务,您可以通过 setter、构造函数或模拟来设置它们 Mockito .
关于java - 为什么组件扫描不适用于 Spring Boot 单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48679637/