简体   繁体   English

使用FakeRequest时模拟内部依赖项

[英]Mocking inner dependency while using FakeRequest

I'm using Play Framework 2.3.x, and I'd like to test that a call to a specific route such as "/" (its router is using several nested @Inject dependencies) ends by calling a specific method on a injected component. 我使用的是Play Framework 2.3.x,我想测试对特定路由(例如,“ /”(其路由器使用了多个嵌套的@Inject依赖项))的调用是否通过在注入的组件上调用特定的方法来结束。

For instance, a classic controller : 例如,经典控制器:

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

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

The service impl injects another service that I want to mock: 该服务会注入另一个我要模拟的服务:

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

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

I'd like to mock call() and retrieve its args to check if they contains the expected things. 我想模拟call()并检索其args以检查它们是否包含预期的东西。

@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
  }
}

I'm calling the route with FakeRequest (and do not inject the controller and calling manually the method) for some annotations to be taken into account and to have a http context (used in some area). 我使用FakeRequest调用路由(不要注入控制器,也不手动调用方法),以便考虑一些注释并具有http上下文(在某些区域使用)。

I'm using Mockito, I've tried several combinaison but couldn't inject my mock (the real method was always called), such as : 我正在使用Mockito,我尝试了几种组合,但是无法注入我的模拟(总是调用真正的方法),例如:

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

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

Is it possible? 可能吗? Do you have an idea? 你有想法吗?

I've stumbled upon https://github.com/sgri/spring-reinject/ which seems to fit (didn't tested) but I'd like to not use another project for something I feel can be done without. 我偶然发现了https://github.com/sgri/spring-reinject/ ,它似乎很合适(未经测试),但我不想在没有我可以做的事情上不使用另一个项目。

Thanks. 谢谢。

The problem reason your DI injector doesn't know anything about this your mock 您的DI喷射器对此一无所知的问题原因

@Mock ExternalService externalService;

Spring context bean set and Mockito mock set initially doesn't have any intersection. Spring上下文bean集和Mockito模拟集最初没有任何交集。

To fix this you should define mock as part of your Spring configuration. 为了解决这个问题,您应该将模拟定义为Spring配置的一部分。 Eg like this 例如这样

@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);
     }     
  }
}

With this code you 使用此代码,您

  1. define additional beans source from MyControllerTest.MyConfig for Spring DI; 从MyControllerTest.MyConfig为Spring DI定义其他bean源;
  2. in mockExternalService method manually create your bean-mock; mockExternalService方法中手动创建您的bean-mock;
  3. define this mock is primary implementation for ExternalService and... 定义此模拟是ExternalService的主要实现,并...
  4. ...lets Spring to know about your bean-mock and autowire the mock anywhere in your system. ...让Spring知道您的bean-mock,并在系统中的任何位置自动装配该模拟。

After this 在这之后

@Autowired 
ExternalService externalService;

you can work with the mock in your tests as usual. 您可以像往常一样在测试中使用模拟程序。 Eg define this behavior 例如定义这种行为

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

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

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