简体   繁体   English

Mockito Spy'ing对被单元测试的对象

[英]Mockito Spy'ing on the object being unit tested

Is it a code smell to spy on an object that is being unit tested? 间谍对正在进行单元测试的物体是否有代码味? For example say I have a LineCounter class whose job is to simply count the number of lines in a string. 例如,假设我有一个LineCounter类,其作用是简单地计算字符串中的行数。 -- -

class LineCounter {
    public int getNumLines(String string) {
        String metadata = getStringMetadata(string);

        // count lines in file
        return numLines;
    }

    /** Expensive operation */
    protected String getStringMetadata(String string) {
        // do stuff with string
    }
}

Now I want to write a JUnit 4 test for this to test the getNumLines method while mocking out the expensive getStringMetadata call. 现在我想为此编写一个JUnit 4测试来测试getNumLines方法,同时getNumLines昂贵的getStringMetadata调用。 I decide to use Mockito's spy mechanism to have getStringMetadata return a dummy value. 我决定使用Mockito的间谍机制让getStringMetadata返回一个虚拟值。

class LineCounterTests {
    @Test public void testGetNumLines() {
        LineCounter lineCounterSpy = Mockito.spy(new LineCounter());

        // Mock out expensive call to return dummy value.            
        Mockito.when(lineCounterSpy.getStringMetadata(Mockito.anyString()).thenReturn("foo");

        assertEquals(2, lineCounterSpy.getNumLines("hello\nworld");
    }
}

Is this a reasonable thing to do? 这是合理的事吗? I feel pretty weird testing a Spy object rather than the actual class, but I can't really think of a reason against it. 我觉得测试一个Spy对象而不是实际的类很奇怪,但是我无法想到反对它的原因。

I will answer the question in two parts. 我将分两部分回答这个问题。 First, yes it is code smell to mock or spy the class under test. 首先,是的,它是代码气味来模拟或监视被测试的类。 That does not mean that it cannot be done correctly but that it is risk prone and should be avoided whenever possible. 这并不意味着它无法正确完成,而是存在风险,应尽可能避免。

WRT your specific example, I would see how the spy could be correctly used but that would be predicated on the assertion that you have elsewhere fully unit tested getStringMetadata . WRT您的具体示例,我将看到如何正确使用间谍,但这将基于您在其他地方完全单元测试的getStringMetadata的断言。 This then begs the question, if you have fully unit tested getStringMetadata elsewhere then you must know how to test it and therefore why not test getNumLines without the spy. 这就引出了一个问题,如果你在其他地方有完全单元测试的getStringMetadata那么你必须知道如何测试它,因此为什么不在没有间谍的情况下测试getNumLines

All this being said, millhouse makes a good point but either way you have to unit test the expensive code somewhere. 所有这一切都说, millhouse提出了一个很好的观点,但无论哪种方式,你必须在某处对昂贵的代码进行单元测试。 His suggestion goes a long way to help isolate the expensive code and ensure that you only have to test / exercise it once. 他的建议有很长的路要走,以帮助隔离昂贵的代码并确保您只需测试/锻炼一次。

In this situation, it is perfectly legitimate to stub the method that is called by the method under test. 在这种情况下,存根被测试方法调用的方法是完全合法的。 It is even the only way I can think of to test it in isolation. 它甚至是我能想到的唯一方法来单独测试它。 You just don't want to extract a single method into it's own class for the sole purpose of testing. 您只是不想将单个方法提取到它自己的类中,仅用于测试。

Beware of the side effects in the stubbed method though. 但要注意存根方法中的副作用。 It might not be sufficient to stub the returned value, if the stubbed method has side effects then you have to stub the side effects as well. 如果存根方法有副作用,那么存储返回值可能还不够,那么你也必须存在副作用。 It might even be a reason against it in some situations where the side effects are very complex, but that would most likely be an indication of a code smell in the implementation of the class under test itself. 在副作用非常复杂的某些情况下甚至可能是反对它的原因,但这很可能是在测试类本身的实现中代码气味的指示。

To answer your question, I find it easy to find reasons for it, but hard to find reasons against it. 要回答你的问题,我觉得很容易找到它的原因,但很难找到反对的理由。 It's the technique I use every day, it helps me split my implementation in small methods that are tested individually in complete isolation, and I haven't seen any limitation to it yet. 这是我每天使用的技术,它帮助我将我的实现分解为完全隔离的单独测试的小方法,我还没有看到任何限制。

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

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