如何对工厂方法进行单元测试?

4

我有一个关于工厂方法单元测试的问题。假设我们有以下代码并希望测试Foo.ToBar方法。

class Bar
{
    public Bar(int someparam)
    {
    }
}

class Foo
{
    int m_someprivate;

    public Foo()
    {
        m_someprivate = 1;
    }

    public Bar TooBar()
    {
        return new Bar(m_someprivate);
    }
}

我看到了两种不同的方法。其中一种可能是这样的:
[Test]
void TooBarTest()
{
    Foo foo = new Foo();

    Bar result = foo.TooBar();

    Assert.AreEqual(new Bar(1), result);
}

很简单明了。但是,我不喜欢它有两个原因:
a) 在测试Foo类时,我们无意中测试了Bar类的一部分。例如,如果Bar构造函数抛出异常,则我们的测试将失败,这有点不对,因为Foo类没有问题,而是Bar类存在问题。
b) 我不喜欢在Assert new Bar(1)中使用生产代码。我更愿意使用一些常量,而不是可能根据某些外部状态(等等)返回不同结果的代码。
我看到的另一种方法是基于创建独立工厂来创建Bar。
class Bar 
{
    public Bar(int someparam)
    {
    }
}

interface IBarFactory
{
    Bar create(int someparam);
}

class BarFactory : IBarFactory
{
    public Bar create(int someparam)
    {
        return new Bar(someparam);
    }
}

class Foo
{
    int m_someprivate;
    BarFactory m_barFactory;

    public Foo()
    {
        m_someprivate = 1;
        m_barFactory = new BarFactory();
    }

    public Bar TooBar()
    {
        return m_barFactory.create(m_someprivate);
    }

    public void setBarFactory(BarFactory barFactory)
    {
        m_barFactory = barFactory;
    }
}


[Test]
void TooBarTest()
{
    Mockery mockery = new Mockery()
    IBarFactory barFactoryMock = mockery.NewMock<IBarFactory>();
    Expect.Once.On(barFactoryMock).Method("create").With(new Object[] { 1 }).Will(Return.Value(new Bar(1)); 

    Foo foo = new Foo();
    foo.setBarFactory(barFactoryMock);

    foo.ToBar();
}

看起来这是更好的方式。但是,我不喜欢我们必须创建工厂接口、工厂、工厂设置器并使测试变得更加复杂,只为了测试一行代码。

你对此有什么想法?你更喜欢什么?你有其他测试方法吗?


可能是单元测试具有具体类作为返回类型的工厂方法的重复问题。 - BrokenGlass
2个回答

4

我同意Tomas Jansson的观点。此外,我会在构造函数中注入IBarFactory,而不是实例化BarFactory。这样,您就永远不必接触Bar或BarFactory。相反,您可以在测试时只需使用存根IBarFactory。


3

我肯定会选择独立的工厂方法。此外,我会将该方法的名称从ToBar更改为其他名称。


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