【问题标题】:How do I unit test Spring Controller using annotations?如何使用注释对 Spring Controller 进行单元测试?
【发布时间】:2018-03-26 12:48:18
【问题描述】:

我不熟悉使用 Spring 控制器进行单元测试的概念。我正在关注我在网上找到的一些示例,并尝试实施他们的测试策略。这是我的基本控制器:

@Controller
public class GreetingController {

    @RequestMapping("/greeting")
    public String greeting(@RequestParam(value = "name2", required = false, defaultValue = "World2") String name2,
                           Model model) {

        model.addAttribute("name", name2);
        return "greeting";
    }

}

这是我的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class ControllerGreetingTest {

    private MockMvc mockMvc;

    @Autowired
    GreetingController greetingController;
    @Test
    public void shouldReturnSomething() throws Exception {
        mockMvc.perform(get("/greeting"))
                .andExpect(status().isOk())
                .andExpect(view().name("greeting"));
    }

}

看起来很简单,但我收到以下错误:

java.lang.IllegalStateException: GenericXmlWebContextLoader 都没有 AnnotationConfigWebContextLoader 也无法检测到默认值,并且 没有为上下文声明 ApplicationContextInitializers 配置 [ContextConfigurationAttributes@1698539 declaringClass = 'com.practice.demo.ControllerGreetingTest',位置 = '{}',类 ='{}',inheritLocations = true,initializers ='{}',inheritInitializers = true,name = [null],contextLoaderClass = 'org.springframework.test.context.ContextLoader']

我假设我必须在 @ContextConfiguration 注释中添加一个参数,但不确定要在其中包含什么。

EDIT = 这是我目前所拥有的:

public class ControllerGreetingTest {

    private MockMvc mockMvc;

   @Before
    public void setup(){
        this.mockMvc = standaloneSetup(new GreetingController()).build();
    }

    @Test
    public void shouldReturnDefaultString() throws Exception {
        mockMvc.perform(get("/greeting"))
                .andExpect(status().isOk())
                .andExpect(view().name("greetings"))
                .andExpect(model().attribute("name","World2"));
    }

}

它完成了这项工作,但它没有像我以前尝试过的那样使用任何 Spring 注释。这种方法不好,所以试图弄清楚为什么每当我在测试文件中包含注释时我都会不断收到错误.

我的 POM:

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>1.5.7.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-all</artifactId>
        <version>1.3</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <artifactId>hamcrest-core</artifactId>
                <groupId>org.hamcrest</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.9.5</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>3.2.3.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>3.4.2</version>
        </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.5.7.RELEASE</version>
        <scope>test</scope>
    </dependency>

</dependencies>

【问题讨论】:

  • 如果我们在谈论 Spring Boot,请尝试使用 @RunWith(SpringRunner.class)
  • @Antoniossss 我正在使用 Spring Boot。当我得到Cannot resolve symbol 'SpringRuner' 时,我在 pom 中包含什么依赖以包含 SpringRunner.class
  • org.springframework.boot:spring-boot-starter-test
  • @Antoniossss 我似乎无法摆脱那个错误,我附上了我的 Maven 依赖项列表..
  • @Antoniossss 我已经解决了有关实施@RunWith(SpringRunner.class) 的问题,但我现在遇到了另一个错误:org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.practice.demo.ControllerGreetingTest': Unsatisfied dependency expressed through field 'greetingController'

标签: java spring spring-mvc spring-boot junit


【解决方案1】:

你应该使用spring-boot-starter-test 依赖。它几乎有所有可供测试的东西。

为了测试 Spring 应用程序的控制器部分,您应该为您的测试类使用 @WebMvcTest 注释。使用此注释,spring 将为控制器部分加载上下文。另外,如果您使用此注释,则不需要设置方法。您可以简单地自动装配 mockMvc。你的测试类应该是这样的:

@RunWith(SpringRunner.class)
@WebMvcTest(GreetingController.class)
public class ControllerGreetingTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private SomeServiceClass someServiceClass;

    @Test
    public void shouldReturnDefaultString() throws Exception {
        mockMvc.perform(get("/greeting"))
            .andExpect(status().isOk())
            .andExpect(view().name("greetings"))
            .andExpect(model().attribute("name","World2"));
    }

}

注意:您的控制器没有任何自动装配字段。如果控制器有一些自动装配的对象,例如服务或存储库对象。您可以简单地使用注释 @MockBean 模拟它们,如您在上面的代码中所见。

请参阅this link 以了解 spring 提供的其他测试切片注释

【讨论】:

    【解决方案2】:

    对于带有org.springframework.boot:spring-boot-starter-test的项目可以使用

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = App.class)
    public class ControllerGreetingTest {
        ...
    }
    

    App.class 是您使用 @SpringBootApplication 注释的主要应用程序类。但你最好阅读documentation。如果您不想包含(classes = App.class) 部分,您也可以更改folder structure

    对于简单的控制器,可以执行简单的独立测试

    @RunWith(SpringRunner.class)
    @WebMvcTest(controllers = ControllerGreeting.class)
    public class ControllerGreetingTest {
        @Autowired
        private MockMvc mockMvc;
    
        ...
    
    }
    

    【讨论】:

      【解决方案3】:

      只需添加@ContextConfiguration 注释并引用一个或多个XML 配置文件位置或一个或多个配置类。否则 Spring 无法自动装配您的控制器,应该对其进行测试。

      示例:您要测试一个控制器,该控制器通过 @Autowired 使用 MyService:

      MyControllerTest:注入控制器,应该使用 MyTestConfig 配置类进行测试。

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes = {MyTestConfig.class})
      @WebAppConfiguration
      public class MyControllerTest {
      
        private MockMvc mockMvc;
      
        @Autowired
        private MyController controller;
      
        @Before
        public void setUp() {
          mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
        }
      
        // Tests
      }
      

      MyTestConfig:返回测试所需的所有 bean。使用 Mockito 模拟控制器的依赖关系,因为我们只想测试控制器而不是服务层。

      @Configuration
      public class MyTestConfig {
      
        @Bean
        public MyService myService() {
          return Mockito.mock(MyService.class);
        }
      
        @Bean
        public MyController myController() {
          return new MyController();
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-08-12
        • 1970-01-01
        • 2017-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多