为什么我需要进行模拟测试?

6

我是新手,对Mockito和PowerMockito都不熟悉。我发现使用纯Mockito无法测试静态方法,因此需要使用PowerMockito(是这样吗?)。

我有一个非常简单的类Validate,其中包含一个非常简单的方法。

public class Validate {
        public final static void stateNotNull(
            final Object object,
            final String message) {
    if (message == null) {
        throw new IllegalArgumentException("Exception message is a null object!");
    }
    if (object == null) {
        throw new IllegalStateException(message);
    }
}

所以我需要验证:

1)当我对空消息参数调用该静态方法时,会调用IllegalArgumentException
2)当我对空对象参数调用该静态方法时,会调用IllegalStateException

到目前为止,我编写了以下测试:

import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isNull;

import org.junit.Before;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.testng.annotations.Test;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Validate.class)
public class ValidateTestCase {

    @Test(expectedExceptions = { IllegalStateException.class })
    public void stateNotNullTest() throws Exception {
        PowerMockito.mockStatic(Validate.class);
        Validate mock = PowerMockito.mock(Validate.class);
        PowerMockito.doThrow(new IllegalStateException())
            .when(mock)
            .stateNotNull(isNull(), anyString());
        Validate.stateNotNull(null, null);
    }
}

这段话表明我在模拟 Validate 类,并检查当该方法被调用时,如果使用空对象作为参数和任何字符串作为消息,则会抛出 IllegalStateException 异常。

现在,我真的不明白。为什么我不能直接调用该方法,放弃围绕静态类进行模拟的整个神秘魔法?似乎除非我调用 Validate.stateNotNull 方法,否则测试都会通过... 我为什么要模拟它呢?

2个回答

11
你不应该嘲笑你正在测试的类和方法。你只应该模拟执行测试所需的方法。
例如,如果你需要一些来自Web服务的对象来执行测试,你可以模拟Web服务调用,这样你就不需要实际调用Web服务。

8
首先,确定您的目标和想要测试的内容。您的测试不是在测试Validate类方法本身,而是创建一个行为类似于该方法的模拟对象,就像Fortega指出的那样。明确您正在测试的内容(测试对象)以及执行测试所需的内容(协作者),然后查看协作者并决定它们是否易于创建或者您是否需要模拟它们。
对于此类没有任何依赖的情况,我建议完全不使用模拟。这里没有需要模拟的内容,测试可以像这样编写:
import static org.junit.Assert.*;

public class ValidateTestCase {

    @Test
    public void testHappyPath() throws Exception {
        Validate.stateNotNull("", "");
    }

    @Test
    public void testNullMessage() throws Exception {
        try {
            Validate.stateNotNull(null, null);
            fail();
        }
        catch (IllegalStateException e) {
            String expected = "Exception message is a null object!"
            assertEquals(expected, e.getMessage());
        }
    }

    @Test(expected=IllegalStateException.class)
    public void testNullObject() throws Exception {
        Validate.stateNotNull(null, "test");
    }
}

这告诉您代码是否符合您的要求。

除非您想避免引入测试中的某些依赖关系,否则不要使用模拟。这些依赖可能是外部资源(如文件系统或数据库)或某些复杂子系统。模拟框架非常有用,但它们增加了复杂性,并且它们可以过度指定它们正在测试的事物的行为,从而使测试变得脆弱,并且可以使测试难以阅读。如果可以,尽量避免使用它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接