如何单位测试工厂方法?

时间:2011-08-02 20:17:52

标签: c# unit-testing

我对工厂方法的单元测试有疑问。 假设我们有以下代码,并想测试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();
}

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

你对此有何看法?你喜欢哪个?你有其他测试方法吗?

2 个答案:

答案 0 :(得分:4)

我与Tomas Jansson结盟。此外,我会在构造函数中注入IBarFactory,而不是实例化BarFactory。因此,您永远不必触摸Bar和BarFactory。相反,您可以在测试时将IBarFactory存根。

答案 1 :(得分:3)

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