我怎么知道在被测单元上是否调用了一个方法?

时间:2012-05-17 15:09:33

标签: java testing tdd mockito

我正在使用mockito在TDD中编写一个新类(Derived),我有以下情况:

班级基础:

public abstract class Base<T>{
    //.......
    protected final T baseCreate(T entity){
        // implementation
    }
}

Class Derived(这是我使用TDD编写的类):

public class Derived extends Base<MyObject> {
    //.......
    public MyObject create(MyObject entity){
        baseCreate(entity);    //This is what I want the implementation to be
    }
}

当我开始编写测试时,会强制我调用baseCreate方法 - 我无法理解如何做到这一点。 有没有办法,使用mockito来验证create(...)中的Derived方法是否会调用baseCreate(...)类中的Base方法?

感谢。

3 个答案:

答案 0 :(得分:5)

单元测试用于测试类的行为,而不是其实现。因此,您不应该关注Base baseCreate()被明确调用,而是调用Derived的{​​{1}}完全按照您对外部观察者的观点所做的那样做

答案 1 :(得分:4)

Attila适用于大多数情况。你想要测试的是创造实际上做了你认为它应该做的事情,而不是它是如何做到的。你在这里的情况听起来像是,“我已经知道baseCreate做了我想要它做的事情,所以我不想重新测试它,只是它被调用。”这个可以,但如果是这样,那么你的超类真的更像是一个合作者。这是支持委托而不是继承的部分原因。尽管如此,有时很难回头改变设计决策,所以你必须测试你的设备。

你仍然应该支持只检查“create”是否完成了你想要它做的事情,但是你可能会遇到这样的情况:baseCreate确实在做很多需要大量协作者设置的东西。这使得测试变得困难和脆弱。在这种情况下,你会想要使用“间谍”。间谍包装一个“真实”对象并委托给真正的方法调用,除非你专门创建另一个期望。

如果你可以公开baseCreate,你可以像这样使用Mockito:

@RunWith(MockitoJUnitRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
public class YourTestCase {
    @Spy
    private Derived classUnderTest = new Derived();

    @Test
    public void privatePartialMockingWithPowerMock() {        
        MyObject myObject = new MyObject();
        when(classUnderTest.baseCreate(myObject)).thenReturn(myObject);

        // execute your test
        classUnderTest.create(myObject);

        verify(classUnderTest).baseCreate(myObject);
    }
}

如果您无法公开baseCreate,我认为您可以使用PowerMock。它允许您验证私有方法,但我认为没有任何理由它也无法执行受保护的方法。

@RunWith(PowerMockRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
@PrepareForTest(Derived.class)
public class YourTestCase {
    @Test
    public void testCreate() {        
        Derived classUnderTest = PowerMockito.spy(new Derived());
        MyObject myObject = new MyObject();

        // use PowerMockito to set up your expectation
        PowerMockito.doReturn(myObject).when(classUnderTest, "baseCreate", myObject);

        // execute your test
        classUnderTest.create(myObject);

        // Use PowerMockito.verify() to verify result
        PowerMockito.verifyPrivate(classUnderTest).invoke("baseCreate", myObject);
    }
}

答案 2 :(得分:1)

你说你正在使用TDD - 所以可能有一些DerivedBase或两者所需行为的规范。因此,您将围绕该规范编写一些测试。这些测试不要求你Derived扩展Base - 他们只需要每个类的某些行为;这将是你可以在不使用继承的情况下实现的行为。

一旦你的测试通过,那么TDD的下一阶段就会开始。这就是“重构”阶段,你可以在那里寻找类设计方式的改进。这是您决定Derived延长Base并使create方法调用baseCreate的点。美妙的是,当你做重构时,你已经进行了一些测试,以确保它能够正常工作。