对这个单元测试感到困惑!

Nob*_*ody 1 c# unit-testing moq xunit .net-4.0

基本上,我有一个抽象类,它有一个唯一的增量ID - Primitive.当实例化一个Primitive(或更确切地说,一个继承者Primitive)时,ID会递增 - 直到ID溢出的点 - 此时,我向异常添加一条消息并重新抛出.

好的,一切正常......但是我正在尝试测试这个功能,我以前从未使用过模拟.我只需要为ID提供足够的原语溢出并声明它在正确的时间抛出.

  • 实例化20亿个对象是不合理的!但是,我没有看到另一种方式.
  • 我不知道我是否正确使用嘲笑?(我正在使用Moq.)

这是我的测试(xUnit):

[Fact(DisplayName = "Test Primitive count limit")]
public void TestPrimitiveCountLimit()
{
    Assert.Throws(typeof(OverflowException), delegate()
    {
        for (; ; )
        {
            var mock = new Mock<Primitive>();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

和:

public abstract class Primitive
{
    internal int Id { get; private set; }
    private static int? _previousId;

    protected Primitive()
    {
        try
        {
            _previousId = Id = checked (++_previousId) ?? 0;
        }
        catch (OverflowException ex)
        {
            throw new OverflowException("Cannot instantiate more than (int.MaxValue) unique primitives.", ex);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为我做错了 - 所以我该怎么测试呢?

Pie*_*kel 5

你不需要嘲笑这个.当两个类一起工作并且你想用mock(假)替换一个类时你使用mocking,所以你只需要测试另一个.在您的示例中不是这种情况.

但是有一种方法可以使用模拟,并修复了2bln实例的问题.如果将ID生成与Primitive类分开并使用生成器,则可以模拟生成器.一个例子:

我已经改为Primitive使用提供的生成器.在这种情况下,它被设置为静态变量,并且有更好的方法,但作为一个例子:

public abstract class Primitive
{
    internal static IPrimitiveIDGenerator Generator;

    protected Primitive()
    {
        Id = Generator.GetNext();
    }

    internal int Id { get; private set; }
}

public interface IPrimitiveIDGenerator
{
    int GetNext();
}

public class PrimitiveIDGenerator : IPrimitiveIDGenerator
{
    private int? _previousId;

    public int GetNext()
    {
        try
        {
            _previousId = checked(++_previousId) ?? 0;

            return _previousId.Value;
        }
        catch (OverflowException ex)
        {
            throw new OverflowException("Cannot instantiate more than (int.MaxValue) unique primitives.", ex);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您的测试用例变为:

[Fact(DisplayName = "Test Primitive count limit")]
public void TestPrimitiveCountLimit()
{
    Assert.Throws(typeof(OverflowException), delegate()
    {
        var generator = new PrimitiveIDGenerator();

        for (; ; )
        {
            generator.GetNext();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

这将运行得更快,现在你只测试ID生成器是否工作.

现在,当您想要测试创建新原语实际上要求ID时,您可以尝试以下方法:

public void Does_primitive_ask_for_an_ID()
{
    var generator = new Mock<IPrimitiveIDGenerator>();

    // Set the expectations on the mock so that it checks that
    // GetNext is called. How depends on what mock framework you're using.

    Primitive.Generator = generator;

    new ChildOfPrimitive();
}
Run Code Online (Sandbox Code Playgroud)

现在您已将不同的问题分开,并可以单独测试它们.