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

标签 c# unit-testing .net-4.0 moq xunit

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

好的,一切都很好......但我正在尝试测试这个功能,我以前从未使用过模拟。我只需要制作足够的 Primitives 以使 ID 溢出并断言它在正确的时间抛出。

  • 实例化 20 亿个对象来做到这一点是不合理的!但是我没有看到另一种方式。
  • 我不知道我是否正确使用了模拟? (我正在使用 Moq 。)

  • 这是我的测试(xUnit):
    [Fact(DisplayName = "Test Primitive count limit")]
    public void TestPrimitiveCountLimit()
    {
        Assert.Throws(typeof(OverflowException), delegate()
        {
            for (; ; )
            {
                var mock = new Mock<Primitive>();
            }
        });
    }
    

    和:
    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);
            }
        }
    }
    

    我认为我做错了 - 那么我该如何正确测试呢?

    最佳答案

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

    但是,有一种方法可以使用模拟,并且可以解决 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);
            }
        }
    }
    

    然后,您的测试用例变为:
    [Fact(DisplayName = "Test Primitive count limit")]
    public void TestPrimitiveCountLimit()
    {
        Assert.Throws(typeof(OverflowException), delegate()
        {
            var generator = new PrimitiveIDGenerator();
    
            for (; ; )
            {
                generator.GetNext();
            }
        });
    }
    

    这将运行得更快,现在您只测试 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();
    }
    

    现在您已经分离了不同的关注点并可以分别测试它们。

    关于c# - 对这个单元测试感到困惑!,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4117894/

    相关文章:

    c# - 您将如何在 C# 3.0 中构建桌面应用程序

    c# - NEST 2.0和ElasticSearch 2.0无法模拟 “return all”查询

    c# - Json RestSharp 反序列化响应数据 null

    unit-testing - 使用 Moq 模拟对象,在进行单元测试时使用 Ninject

    javascript - 特殊字符转html代码C#

    unit-testing - 单元测试 - 视频或播客

    unit-testing - 将项目升级到 NuGet 3.0 后运行 AutoFixture xUnit Theory 时出现问题

    c# - 在 C# 中使用泛型 - 从泛型类调用泛型类

    c# - 协方差也在 3.5/2.0 中?

    c# - 任务在哪个核心上运行?