简体   繁体   English

测试有依赖关系的Spring Boot控制器? (JUNIT)

[英]Testing a spring boot controller which has dependencies? (jUnit)

I have this test class : 我有这个测试课:

@RunWith(SpringRunner.class)
@WebMvcTest(ClassToBeTested.class)
public class ClassToBeTestedTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void simpleTestMethodToGetClassWorking(){
        Assert.assertTrue(true);
    }
}

but in the class I want to test, I have this line : 但是在我要测试的课程中,我有这行:

@Autowired
AnnoyingServiceWhichIsADependency annoyingDependency;

So when I try to run the test class - I get this error : 因此,当我尝试运行测试类时,出现此错误:

java.lang.IllegalStateException: Failed to load ApplicationContext

and the cause by line seems to throw this up : 和逐行原因似乎抛出了这个:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ClassToBeTested': Unsatisfied dependency expressed through field 'AnnoyingServiceWhichIsADependency'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '<package-path>.AnnoyingServiceWhichIsADependency' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

I will add that the actual class does work, and does what it is meant to do, but I am having trouble making it work in the unit test world. 我要补充的是,实际的类确实可以正常工作,并且可以完成它的本意,但是我在使它在单元测试领域中工作时遇到了麻烦。

All help appreciated. 所有帮助表示赞赏。

The reason a bean is not created for the dependency class is that you're using @WebMvcTest and not @SpringBootTest : only controllers and the MVC infrastructure classes are scanned. 未为依赖关系类创建bean的原因是,您使用的是@WebMvcTest而不是@SpringBootTest :仅扫描控制器和MVC基础结构类。 From the docs : 文档

Can be used when a test focuses only on Spring MVC components. 当测试仅针对Spring MVC组件时可以使用。

Since it's an MVC test, you can mock the service dependency. 由于它是MVC测试,因此可以模拟服务依赖关系。 Example: https://reflectoring.io/spring-boot-web-controller-test/ 示例: https//reflectoring.io/spring-boot-web-controller-test/

Your test application context is trying to load your ClassToBeTested but is unable to find one of its dependencies and complains about it via that error. 您的测试应用程序上下文正在尝试加载ClassToBeTested,但无法找到其依赖项之一,并通过该错误进行投诉。 Basically you need to have a @Bean of that type in your test context. 基本上,您需要在测试上下文中具有该类型的@Bean。 An option will be to create a TestConfig class which provides a Mock/Spy of that dependency via @Bean annotation. 一个选项是创建一个TestConfig类,该类通过@Bean批注提供该依赖项的Mock / Spy。 In your test you will have to load inside the context via the @ContextConfiguration annotation this test config you just created. 在测试中,您将必须通过@ContextConfiguration批注在刚才创建的测试配置中加载上下文。

https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-testing-annotation-contextconfiguration https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-testing-annotation-contextconfiguration

@WebMvcTest is only going to scan the web layer- the MVC infrastructure and @Controller classes. @WebMvcTest仅用于扫描Web层-MVC基础结构和@Controller类。 That's it. 而已。 So if your controller has some dependency to other beans from, eg form your service layer, they won't be found to be injected. 因此,如果您的控制器对其他Bean有某种依赖性,例如从您的服务层形成的其他Bean,则不会发现它们被注入。

If you want a more comprehensive integration test, use @SpringBootTest instead of @WebMvcTest 如果要进行更全面的集成测试,请使用@SpringBootTest而不是@WebMvcTest

If you want something closer to a unit test, mock your dependency. 如果您想要更接近单元测试的内容,请模拟您的依赖关系。

Also note that Field injection (@Autowired directly on the field) is not recommended exactly for these reasons. 还要注意,由于这些原因,不建议完全使用现场注入(@Autowired直接在现场)。 I recommend you change to constructor injeciton ( add a constructor for Classtobetested and place the @Autowired annotation on it. ) Then for a unit test you can pass in a mock. 我建议您更改为构造函数注入(为Classtobetested添加一个构造函数,并在其上放置@Autowired批注。)然后对于单元测试,您可以传递一个模拟。 Constructor injection leads to a more testable and configurable design. 构造函数注入导致更可测试和可配置的设计。

Just mock that dependency. 只是嘲笑这种依赖性。 Assuming that AnnoyingServiceWhichIsADependency is an interface: 假设AnnoyingServiceWhichIsADependency是一个接口:

@RunWith(SpringRunner.class)
@WebMvcTest(ClassToBeTested.class)
public class ClassToBeTestedTests {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private AnnoyingServiceWhichIsADependency annoyingDependency;

    @Test
    public void simpleTestMethodToGetClassWorking(){
        Assert.assertTrue(true);
    }
}

Use Mockito when and thenReturn methods to instruct the mock. 使用Mockito whenthenReturn方法来指导模拟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM