22

我开发了一些具有相似行为的类,它们都实现了相同的接口。我实现了一个创建适当对象并返回接口的工厂。我正在为工厂编写单元测试。你得到的只是对象的接口。测试工厂是否正常工作的最佳方法是什么?

我想知道 Java 的答案,但如果有跨语言的解决方案,我想知道。

2号。在答案中,会像其他答案一样完成吗?如果是这样,我也会将另一个答案标记为已接受,并改写我的问题以解决返回接口的工厂并且您不知道实现该接口的具体类的类型,以及您确实知道具体类是什么的情况用过的。

4

5 回答 5

46

你想做的不是单元测试

如果您测试返回的对象是否是特定具体类的实例,则不是单元测试。你是集成测试。虽然集成测试很重要,但它不是一回事。

在单元测试中,您只需要测试对象本身。如果您断言返回的抽象对象的具体类型,则您正在测试返回对象的实现。

一般对象的单元测试

当单元测试时,有四件事,你要断言:

  1. 查询(非 void 方法)的返回值是您所期望的。
  2. 命令的副作用(void 方法)会按照您的期望修改对象本身。
  3. 接收发送到其他对象的命令(这通常使用模拟来完成)。

此外,您只想测试可以从对象实例(即公共接口)观察到的内容。否则,您将自己与一组特定的实现细节联系在一起。当这些细节发生变化时,这将要求您更改测试。

单元测试工厂

对工厂进行单元测试真的很无趣,因为您对返回的查询对象的行为不感兴趣。该行为(希望)在其他地方进行了测试,可能是在对该对象本身进行单元测试时进行的。您只对返回的对象是否具有正确的type真正感兴趣,如果您的程序编译,则可以保证这一点。

由于工厂不会随着时间而改变(因为那时它们将是“建造者”,这是另一种模式),因此没有要测试的命令。

工厂负责实例化对象,因此它们不应依赖其他工厂为它们执行此操作。它们可能依赖于 Builder,但即便如此,我们也不应该测试 Builder 的正确性,只测试 Builder 是否收到消息。

这意味着您对工厂的所有测试都是它们是否将消息发送到它们所依赖的对象。如果您使用依赖注入,这几乎是微不足道的。只需在单元测试中模拟依赖项,并验证它们是否接收到消息。

单元测试工厂总结

  1. 不要测试返回对象的行为和实现细节!您的工厂不负责对象实例的实现!
  2. 测试是否收到发送到依赖项的命令。

就是这样。如果没有依赖项,则无需测试。除了可能断言返回的对象不是null引用。

集成测试工厂

如果您要求返回的抽象对象类型是特定具体类型的实例,那么这属于集成测试。

这里的其他人已经回答了如何使用instanceof操作符来做到这一点。

于 2015-12-10T10:14:33.670 回答
23

由于我不知道您的工厂方法是什么样的,所以我现在只能建议

  1. 检查对象是否是您正在寻找的正确的具体实现:

    IMyInterface fromFactory = factory.create(...);  
    Assert.assertTrue(fromFactory instanceof MyInterfaceImpl1);
    
  2. 您可以检查工厂是否使用有效的实例变量设置了具体实例。

于 2008-09-01T00:47:22.907 回答
0
if (myNewObject instanceof CorrectClass)
{
    /* pass test */
}

更新:

不知道为什么这个被标记了,所以我会扩大一点......

public void doTest()
{
    MyInterface inst = MyFactory.createAppropriateObject();
    if (! inst instanceof ExpectedConcreteClass)
    {
        /* FAIL */
    }
}
于 2008-09-01T00:49:18.517 回答
0

@cem-catikkas 我认为比较 getClass().getName() 值会更正确。在 MyInterfaceImpl1 类是子类的情况下,您的测试可能会被破坏,因为子类是 MyInterfaceImpl1 的 instanceof。我将重写如下:

IMyInterface fromFactory = factory.create(...);  
Assert.assertEquals(fromFactory.getClass().getName(), MyInterfaceImpl1.class.getName());

如果您认为这可能会以某种方式失败(我无法想象),请进行两次验证。

于 2008-09-02T12:22:57.703 回答
0

如果您的 Factory 返回一个具体实例,您可以使用@Parameters注释以获得更灵活的自动单元测试。

package it.sorintlab.pxrm.proposition.model.factory.task;

import org.junit.Test;

import java.util.Arrays;
import java.util.Collection;

import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import static org.junit.Assert.*;

@RunWith(Parameterized.class)
public class TaskFactoryTest {

    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { "sas:wp|repe" , WorkPackageAvailabilityFactory.class},
                { "sas:wp|people", WorkPackagePeopleFactory.class},
                { "edu:wp|course", WorkPackageCourseFactory.class},
                { "edu:wp|module", WorkPackageModuleFactory.class},
                { "else", AttachmentTaskDetailFactory.class}
        });
    }

    private String fInput;
    private Class<? extends TaskFactory> fExpected;

    public TaskFactoryTest(String input, Class<? extends TaskFactory> expected) {
        this.fInput = input;
        this.fExpected = expected;
    }

    @Test
    public void getFactory() {
        assertEquals(fExpected, TaskFactory.getFactory(fInput).getClass());
    }
}

这个例子是使用Junit4制作的。您会注意到,只需一行代码,您就可以测试 Factory 方法的所有结果。

于 2018-08-13T08:04:52.123 回答