1

我正在尝试为我的控制器提供一个干净的单元测试。这个控制器有一个服务作为依赖,这个服务有一个数据源作为依赖。

测试看起来像这样:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class ContentActionWebServiceControllerTest {
  @Autowired
  private WebApplicationContext wac;

  private MockMvc mockMvc;

  @Autowired
  private MyService myService;

  @Test
  public void getRequestActionList() throws Exception {
    when(...)
    perform(...);
    verify(...);
  }

  @Configuration
  @ImportResource("...")
  static class MyTestConfiguration {

    @Bean
    public MyService myService() {
      return Mockito.mock(MyService.class);
    }
  }
}

MyService 类似于

@Service
public class MyService {
  @Autowired
  private MyDataSource myDatasource;

  ...
}

因为 MyService 作为 Autowired 属性 MyDataSource,所以上下文没有被初始化,因为它没有找到任何满足 MyService 的 @Autowired 注解的 MyDataSource 类型。但是为什么它会尝试解决这个注释呢?这是模拟吗?

4

2 回答 2

4

Mockito 确实使用 cglib 来创建一个新的子类MyService(并用模拟方法覆盖所有方法)。

但是仍然会注入父级的依赖项,因为这是 Spring 的工作方式:

如果你有一个包含一些@Autowired字段的父类,以及一个继承自这个父类的子类,那么 Spring@Autowired在实例化子类时会注入父类的字段。我想在你的情况下这是相同的行为。

如果您使用接口MyService,那么您的问题将得到解决。

于 2013-04-10T21:00:49.397 回答
1

如果它应该是一个单元测试(而不是一个集成测试),你甚至不需要使用 Spring,你可以用 JUnit+Mockito 来完成。您可以简单地创建支持对象的模拟(通过)并将它们注入到被测试者(通过),而不是@Autowire从 Spring 上下文中获取依赖项。我相信您的代码可以简化为(从概念上)如下所示:@Mock@InjectMocks

@RunWith(MockitoJUnitRunner.class)
public class ContentActionWebServiceControllerTest {

  @Mock
  private Service mockServiceUsedByController;

  @InjectMocks
  private YourController testee;

  @Test
  public void getRequestActionList() throws Exception {
    assertFalse(testee.getRequestActionList().isEmpty());
    // etc.
  }
}
于 2013-04-10T21:21:38.910 回答