java - 使用 FakeRequest 时模拟内部依赖

标签 java playframework dependency-injection mockito

我正在使用 Play Framework 2.3.x,并且我想测试对特定路由(例如“/”)的调用是否通过调用特定方法来结束注入(inject)的组件。

例如,经典 Controller :

public class MyController extends Controller {
  @Inject private MyService myService;

  public Result index() { myService.foo(); }
  ...

 

服务实现注入(inject)了我想要模拟的另一个服务:

@Service
public class MyServiceImpl implements MyService {
  @Inject private ExternalService externalService;

  public void foo() { externalService.call(...); }
  ...

我想模拟 call() 并检索其参数以检查它们是否包含预期的内容。

@RunWith(SpringJUnit4ClassRunner.class)
@Profile("test")
@ContextConfiguration(classes = ApiConfiguration.class)
public class MyControllerTest {
  @Test public void test() {
    Result result = routeAndCall(new FakeRequest("GET", "/"), 10000);
    // here, I expect to retrieve and test the args of a mocked externalService.call
  }
}

我使用 FakeRequest 调用路由(并且不注入(inject) Controller 并手动调用方法),以便考虑一些注释并拥有 http 上下文(在某些区域使用)。

我正在使用 Mockito,我尝试了几种组合,但无法注入(inject)我的模拟(总是调用真正的方法),例如:

@Before public void initMocks() {
   MockitoAnnotations.initMocks(this);
}

@Mock ExternalService externalService;
...
when(externalService.call().then(invocation -> {
  Object[] args = invocation.getArguments();

这可能吗?你有什么想法吗?

我偶然发现了https://github.com/sgri/spring-reinject/这似乎适合(未测试),但我不想使用另一个项目来完成我认为不需要的事情。

谢谢。

最佳答案

问题原因是你的 DI 注入(inject)器对你的模拟一无所知

@Mock ExternalService externalService;

Spring 上下文 bean 集和 Mockito 模拟集最初没有任何交集。

要解决此问题,您应该将模拟定义为 Spring 配置的一部分。例如。像这样

@RunWith(SpringJUnit4ClassRunner.class)
@Profile("test")
@ContextConfiguration(classes = {ApiConfiguration.class, MyControllerTest.MyConfig.class})
public class MyControllerTest {

 @Autowired 
 ExternalService externalService;

  @Test public void test() {
     ...
  }

  @Configuration
  public static class MyConfig {
     @Bean 
     @Primary // it tells Spring DI to select your mock instead of your real ExternalService impl
     public ExternalService mockExternalService() {
         return Mockito.mock(ExternalService.class);
     }     
  }
}

使用此代码,您

  1. 从 MyControllerTest.MyConfig 为 Spring DI 定义其他 bean 源;
  2. mockExternalService 方法中手动创建你的 bean-mock;
  3. 定义此模拟是ExternalService 的主要实现,并且...
  4. ...让 Spring 了解您的 bean-mock 并在系统中的任何位置 Autowiring 该模拟。

在此之后

@Autowired 
ExternalService externalService;

您可以像往常一样在测试中使用模拟。例如。定义此行为

Mockito.doThrow(NullPointerException.class).when(externalService).call(...);

关于java - 使用 FakeRequest 时模拟内部依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35635888/

相关文章:

java - 将 JPG 转换为具有背景透明度的 PNG

jvm - java编译时错误,由于从jdk7降级到jdk6

playframework - 在运行时使用 build.sbt 中的 javaOptions

java - 如何通过 SSH 连接在 Linux 上保持运行程序?

java - java中如何通过接口(interface)实现多继承?

java - 如何找到 Play Framework 应用程序的绝对路径?

twitter-bootstrap - Play 框架中的 Twitter Bootstrap 助手是否已弃用?

java - 某些类中的 Spring Boot : Autowired CRUDRepository null,

asp.net-mvc - 使用 ASP.New MVC 4 Web Api 进行授权过滤器依赖注入(inject)

dependency-injection - 从 Angular2 中的子组件访问父组件数据/属性