在调用层次结构中插入模拟对象

时间:2018-03-28 03:56:00

标签: java unit-testing mocking mockito

我正在编写我的第一个单元测试(使用Mockito)。我想测试的功能结构如下:

class ClassA {
    public ClassB b;

    public void methodA() {
        // calls a method of ClassB
        b.methodB();
    }
}

class ClassB {
    public ClassC c;

    public void methodB() {
        // calls a method of ClassC
        someVariable = c.methodC();
    }
}

class ClassC {

    public Object methodC() {
        // do something
        // this method needs to be mocked for testing (needs to return dummy values to ClassB)
    }
}

我真正希望测试的是ClassB中引入的某项功能是否仍然有效。为此,我需要methodC()(从ClassB调用)来返回某些值,因此我嘲笑ClassC

我的问题是,我遇到的所有教程都没有显示正在测试的类是从另一个类调用的(就像我的情况一样 - ClassBClassA调用)。

此外,教程显示被测试的类的实例被模拟,与我的情况不同(我正在测试ClassB但需要模拟ClassC)。

我应该如何为ClassB编写单元测试?我对这个单元测试的看法如下:

@RunWith(MockitoJUnitRunner.class)
class TestB {

    public ClassA instanceA;

    public ClassB instanceB;

    @Mock
    public ClassC instanceC;        

    public void setUp() {
        // do setup stuff
        when(instanceC.methodC()).thenReturn(dummyValue);
        b.setC(instanceC);
    }

    @Test
    public void Test() {

    }
}

我还没有尝试过这个,但我想知道这种方法是否合理,或者我的单元测试是否被错误地建模。谢谢!

3 个答案:

答案 0 :(得分:1)

  

我的问题是,我遇到的所有教程都没有显示正在测试的课程是从另一个类调用的

你不应该担心。当您测试ClassB时,您无需考虑其来电者。此时您唯一的目标是测试ClassB的功能,而不是其他任何内容。

因此,您可以从public ClassA instanceA;课程中删除TestB。您的setUp方法看起来不错。

以下是您的测试方法的外观

@Test
public void test_methodB() {
    instanceB.methodB();
    //Rest depends on the logic within methodB. Maybe use Mockito verify to verify certain calls were made, use Answers etc.
}
  

此外,教程显示了被测试的类的实例被模拟

我不明白为什么需要嘲笑被测系统。

答案 1 :(得分:0)

正如user7所提到的,你永远不应该模拟被测试的类。模拟应该用于模拟依赖类,这样你就不必创建依赖类(假设它在构造函数中需要3个参数,每个参数需要进一步的参数来构造它们;为了避免这种情况,我们用mock)。不是创建依赖类实例,而是模拟它,并设置预期行为(使用when(mockedObject.someMethod()).return(dummyValue))并仅测试您的类。如果依赖类的行为应该如此,我的类的行为是否符合我的预期?所以,你的setUp方法是正确的。您可以设置ClassC的期望值,然后测试ClassB。

答案 2 :(得分:0)

只需订购一下@ user7所说的更容易一点。

  1. 你应该有3个测试条款(ClassATest,ClassBTest,ClassCTest)
  2. 在ClassATest中你应该模拟正在使用的classB的实例,并确保在instaceA.methodA()上调用methodB(你可以查找Mockito.verify)
  3. 在ClassBTest中你应该模拟正在使用的classC的实例,并确保在instaceB.methodB()上调用methodC(与以前一样,同时查看InjectMocks注释)

    @RunWith(MockitoJUnitRunner.class)
    class TestB {
    
      @InjectMocks
      public ClassB instanceB;
    
      @Mock
      public ClassC instanceC;        
    
      public void setUp() {
        // do setup stuff
        when(instanceC.methodC()).thenReturn(dummyValue);
      }
    
      @Test
      public void Test() {
        instaceB.methodB();
      }
    }
    
  4. 在ClassCTest中,您应该测试methodC上的所有逻辑。