java - Mockito 在使用@Mock 时将空值注入(inject) Spring bean?

标签 java spring unit-testing mockito

因为我是 Spring Test MVC 的新手,所以我不明白这个问题。我从 http://markchensblog.blogspot.in/search/label/Spring 中获取了以下代码

变量 mockproductService 不是从 Application Context 注入(inject)的,它包含 null 值,同时使用 @Mock 注释并获取 Assets 错误。

我目前遇到的Assertion错误如下:

java.lang.AssertionError: Model attribute 'Products' expected:<[com.pointel.spring.test.Product@e1b42, com.pointel.spring.test.Product@e1f03]> but was:<[]>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
    at org.springframework.test.web.servlet.result.ModelResultMatchers$2.match(ModelResultMatchers.java:68)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141)
    at com.pointel.spring.test.ProductControllerTest.testMethod(ProductControllerTest.java:84)

注意:如果我使用 @Autowired 而不是 @Mock,它工作正常。

测试 Controller 类

RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations={"classpath:mvc-dispatcher-servlet.xml"})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class})
public class ProductControllerTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

   @InjectMocks
    private ProductController productController;

    @Mock
    //@Autowired
    private ProductService mockproductService;


    @Before
    public void setup() {

    MockitoAnnotations.initMocks(this);

    List<Product> products = new ArrayList<Product>();
    Product product1 = new Product();
    product1.setId(new Long(1));

    Product product2 = new Product();
    product2.setId(new Long(2));

    products.add(product1);
    products.add(product2);

    Mockito.when(mockproductService.findAllProducts()).thenReturn(products);

    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();

    }

    @Test
    public void testMethod() throws Exception {

    List<Product> products = new ArrayList<Product>();

    Product product1 = new Product();
    product1.setId(new Long(1));

    Product product2 = new Product();
    product2.setId(new Long(2));

    products.add(product1);
    products.add(product2);

    RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/products");

    this.mockMvc.perform(requestBuilder).
        andExpect(MockMvcResultMatchers.status().isOk())
        .andExpect(MockMvcResultMatchers.model().attribute("Products", products))
           //.andExpect(MockMvcResultMatchers.model().size(2))
        .andExpect(MockMvcResultMatchers.view().name("show_products"));


    }
}

Controller 类

@Controller
public class ProductController {

    @Autowired
    private ProductService productService;

    @RequestMapping("/products")
    public String testController(ModelMap model){
        model.addAttribute("Products",productService.findAllProducts());
        return "show_products";
    }
}

WebServletContext mvc-dispatcher-servlet.xml

<bean id="someDependencyMock" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.pointel.spring.test.ProductService" />
</bean>
    <context:component-scan base-package="com.pointel.spring.test" />

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" >     
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

最佳答案

对我来说,不清楚您从引用的博客源中获取的 Spring 和 Mockito 的组合应该如何按预期工作。至少我可以解释你的观察:

  • 您的测试 (this.mockMvc.perform()) 正在 Spring 创建的 Web 应用程序上下文中运行。在该上下文中,ProductController 由 Spring (context:component-scan) 实例化。 productService 然后与您在 mvc-dispatcher-servlet.xml 中创建的 Mockito 模拟 Autowiring 为 someDependencyMock
  • 如果您通过@Autowired 注入(inject)mockproductServiceSpring 会从其上下文中注入(inject)someDependencyMock 实例。因此,您的 Mockito.when() 调用在此实例上正常工作,如前所述,该实例已正确连接到 ProductController
  • 但是,如果您通过 @Mock 注入(inject) mockproductServiceMockito 会注入(inject) 实例ProductService,不是 Spring 上下文之一,因为它对 Spring 一无所知。因此,您的 Mockito.when() 调用不会对 Spring Autowiring 的模拟进行操作,因此 someDependencyMock 保持未初始化状态。

所以我不清楚博客中的原始代码是如何工作的:

  • @InjectMocks 注释的 productController 属性将由 Mockito 初始化,甚至正确连接到测试类中的 mockproductService。但是 Spring 对该对象一无所知,也不会在 this.mockMvc.perform() 调用中使用它。所以我假设如果你只用 @Autowired 注入(inject) mockproductService 你的测试会按预期工作,即使你同时删除了 productController 属性和 MockitoAnnotations.initMocks() 在您的测试类中调用。

关于java - Mockito 在使用@Mock 时将空值注入(inject) Spring bean?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16062842/

相关文章:

java - Sqoop导入表报错ORA-01843

java - 无法使用 gradle 构建项目 Sagan

spring - 没有定义类型的唯一 bean : expected single bean but found 0:

c# - 模拟 'System.Console' 行为

ios - 在 XCTestCase 中对类方法进行单元测试

java - 如何检测用户输入文本的语言?

java - 如何在TextView中显示HTML文本?

java - 我怎样才能改变这个java代码,以便它再次询问密码是否无效?

java - @NonNull 注释允许在验证中使用空值

c# - 重写操作系统查询方法以使其可测试