开发者

How to unittest factory method?

I have a question regarding unit-testing of factory method. Let say we have following code and want to test Foo.ToBar method.

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

class Foo
{
    int m_someprivate;

    public Foo()
    {
        m_someprivate = 1;
    }

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

I saw two different methods. One of them will be something like that

[Test]
void TooBarTest()
{
    Foo foo = new Foo();

    Bar result = foo.TooBar();

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

It's very straight forward. However, I don't like it for two reasons

a) We inadvertent test part of Bar class while testing Foo class. As example, if Bar constructor throws than our test will fail, which is kind of wrong, because Foo class is fine. It's a Bar class which have a problem.

b) I don't like that production code is used in Assert new Bar(1). I would rather prefer to use some constant than some code which may as example return different results depending on some external state (etc).

The other method which I saw is based on creation of standalone factory, which w开发者_如何学JAVAill create 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();
}

It looks like it's better way. However, I don't like that we have to create factory interface, factory, factory setter and make test more complex, just to test 1 line of code.

What are your thoughts on that? What do you prefer? Do you have any other method of testing it?


I aggree with Tomas Jansson. Further I would inject IBarFactory in the constructor instead of instantiating BarFactory. Thus you never have to touch neither Bar nor BarFactory. Instead you can just stub IBarFactory when testing.


I would definitely go for the stand alone factory method. Also, I would change the name of the method from ToBar to something else.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜