用Mockito模拟更深层次的类/接口

时间:2017-06-15 11:12:11

标签: java mockito

我发现与Mockito嘲笑的任何例子与此类似(这些只是代码管理):

假设:

public interface MyInterface {
  public String doWhatever();
}

public class MyClass {
  @Autowired
  MyInterface myInterface;

  public String doSomething() {
    return myInterface.doWhatever();
  }
}

嘲讽:

@Mock
MyInterface myInterfaceMock;

@InjectMocks
MyClass myClass;

@Test
public void test() throws Exception {
    when(myInterfaceMock.doWhatever()).thenReturn("foo");

    String result = myClass.doSomething();
    ...
}

然而,在引入第二课时,使用更深层次:

public class MyOtherClass {
    @Autowired
    MyInterface myInterface;

    public MyInterface getMyInterface() {
        return myInterface;
    }
}

更深层次模拟的类结构总是这样做:

public class MyClass {
    MyOtherClass myOtherClass = new MyOtherClass();

    public MyOtherClass getOtherClass() {
        return myOtherClass;
    }
}

@Test
public void test() throws Exception {
    given(myClass.getOtherClass().getMyInterface().doSomething()).willReturn("bar");        

    String result = myClass.getOtherClass().getMyInterface().doSomething();
}

有关更多information

的信息,请参阅此深层存根示例

但是,这并不反映我应该测试的班级结构。给定的结构如下:

public interface MyInterface {
  public String doWhatever();
}

public class MyOtherClass {
  @Autowired
  MyInterface myInterface;

  public String doOtherThing() {
    return myInterface.doWhatever();
  }
}

public class MyClass {
  MyOtherClass myOtherClass = new MyOtherClass();

  public String doSomething() {
    return myOtherClass().doOtherThing();
  }
}

现在,我想嘲笑它类似于:

@Mock
MyInterface myInterfaceMock;

@InjectMocks
MyClass myClass;

@Test
public void test() throws Exception {
    when(myInterfaceMock.doWhatever()).thenReturn("foo");

    String result = myClass.doSomething();
    ...
}

当然,这不起作用,因为模拟必须在MyOtherClass中注入,而不是在MyClass中注入。但是,如果我将它注入MyOtherClass,我没有MyClass的实例。

编辑:

引起我这个问题的原因是,我应该做微服务水平测试。可能是,我有错误的做法。我也可以通过模拟MyOtherClass测试单元测试MyClass,并通过模拟MyInterface对单元测试MyOtherClass进行测试。

因此,这里有一些关于给定微服务的更多细节:

REST-API - > SomeCode - > SomeOtherCode - >其他-REST-API

Out代码涵盖REST-API,SomeCode和SomeOtherCode。其他-REST-API是第三方,如谷歌,移动服务提供商等。

现在,我能够使用MockMVC测试REST-API并模拟SomeCode。而且我可以通过模拟Other-REST-API对SomeOtherCode进行单元测试。但是,我的目标是使用MockMVC测试整个链,进行一些参数变化并模拟Other-TEST-API,以查看SomeCode和SomeOtherCode的行为。

2 个答案:

答案 0 :(得分:0)

所以发生的事情是@InjectMocks模拟正在寻找注入MyClass内的自动装配的东西时,MyClass没有,所以它找不到任何东西。

如果MyOtherClass@Autowired,我怀疑这会有用,但您可能也需要为@InjectMocks执行MyOtherClass

答案 1 :(得分:0)

根据您的更新: 您应该看看https://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html - 在这里您可以看到如何运行集成测试。您可以提供自己的spring-xml

@ContextConfiguration("/test-config.xml")
public class XmlApplicationContextTests {
    // class body...
}

或弹簧配置测试中的一个类。

@ContextConfiguration(classes = TestConfig.class)
public class ConfigClassApplicationContextTests {
    // class body...
}

此外,您可以使用

为xml定义模拟和间谍
<bean id="spyService" class="org.mockito.Mockito" factory-method="spy">
    <constructor-arg ref="service"/>
</bean>
<bean id="mockService" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="your.Service" /> 
</bean> 

或配置

@Configuration
static class TestConfig {
    @Bean
    Service serviceMock() {
        return mock(Service.class);
    }
    @Bean
    Service serviceSpy() {
        return spy(new Service());
    }
}

但实际上这就是你用spring进行集成测试的方法。

在这种情况下,您还需要提供正确的UnitTestRunner SpringJUnitRunner。你应该得到类似的东西:

@RunWith(SpringJUnitRunner.class)
@ContextConfiguration(classes = TestConfig.class)
public class MyClassComponentTest {
    @Autowired
    MyInterface myInterfaceMock;

    @Autowired
    MyClass myClass;

    @Configuration
    static class TestConfig {
        @Bean
        MyClass myClass() {
            return new MyClass();
        }
        @Bean
        MyOtherClass myOtherClass() {
            return new MyOtherClass();
        }
        @Bean
        MyInterface myInterfaceMock() {
            return mock(MyInterface.class);
        }
    }

    @Test
    public void test() throws Exception {
        when(myInterfaceMock.doWhatever()).thenReturn("foo");

        String result = myClass.doSomething();
        ...
    }
}

旧回答

  

问题是:&#34;实际上是否想要进行单元测试?&#34;

     

因为当你进行单元测试时,你根本不在乎什么   发生在MyOtherClass内。你只需要模拟MyOtherClass,   并为你嘲笑的MyOtherClass写一个自己的Unittest   MyInterface

     

我在你的例子中看到的另一个问题是,你永远不会   实例化一个类MyOtherClass的对象,那个是   永远不会注入你的MyClass - 对象,所以实际上并没有   工作