如何在 NUnit 中测试同一类型的多个对象

How to test multiple objects of the same type in NUnit

我目前是第一次尝试学习 NUnit。

对于我想使用 TDD 开发的 C# 程序,我决定先编写 User class。这个 User class 将(语义上)看起来像这样:

using System;

namespace SSH_file_drop
{
    public class User
    {
        private Boolean authenticated = false;

        public string userName = null;

        //one-time object 'transmission' instance to allow single-use file transmission field
        Transmission fileVehicle = null;

        //property to discern whether user has been correctly authenticated
        public Boolean isAuthenticated 
        {
            get;
        }

        public Boolean canSend ()
        {
            if (authenticated)
            {
                return this.userType != "sender";
            }
            return false;
        }

        public User(String inputUName)
        {
            String userName = inputUName;
        }

        public static void generateUser(string userName)
        {
            //contact server to attempt to register new user
        }

        public void ChangePassword(String oldPassword, String newPassword)
        {
            //ask server to change user password
        }

        public Boolean SetUpTransmission()
        {
            if (canSend())
            {
                try
                {
                    fileVehicle = new Transmission(this);
                    return true;
                }
                catch (e)
                {
                    //write exception message
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }
}

目前真的只是占位符代码。

为了测试 User class 但是我正在尝试编写一个 TestFixture 来创建用户 class 的单独实例,并以某种方式持久存储它们直到拆卸,执行对每个对象进行相同的测试。

我的想法是创建一个 User 对象数组作为 TestCase 数据源,以通过 [Order(<n>)] 属性(栏用户实例初始化测试方法)按顺序测试所有内容,但我已经阅读here 将在运行时为其中的每个方法创建 TestFixture 的新实例,因此我无法以这种方式修改测试夹具中的持久数据。

因为我正在尝试实现有状态逻辑 - User 对象 isAuthenticated() (并且此身份验证依赖于此后的后续测试,因为所有用户数据都被建模为存储在远程数据库中),是有没有一种方法可以在不使用重复操作(创建对象、验证、检查用户类型等)并因此创建多个断言的情况下创建测试?

我们在这种情况下采用的方法是创建辅助方法,以制造具有适当状态的被测 class 实例。

这实际上就是您提到的方法,只是方法略有不同。

你提出的方法要考虑的其他问题,我建议的方法会避免,是有序的 and/or 并行执行测试:如果你有一系列有状态的对象,测试将无法可靠地 运行 并行或乱序。

请注意,为了完全支持这种测试开发模式,您可能需要引入仅测试方法 and.or 构造函数。

例如,您 class 中的 IsAuthenticated 是只读的 属性。为了模拟此 属性 打开或关闭,您可能需要引入一个仅用于测试的构造函数(我倾向于避免这样做,因为有人会在某些时候使用它,即使您已经记录它仅用于测试) 或更改 属性 的实现并添加 setter 方法。

如果您将 Authenticated 属性 更改为使用后备存储成员,那么您可以添加一个仅测试方法(尽管其他开发人员有可能使用此方法,如果它很好- named,使用起来比构造函数更明显)。

private bool m_IsAuthenticated;

public bool IsAuthenticated {
  get {
    return m_IsAuthenticated;
  }
}

public void Set_IsAuthenticated_ForTestONLY(bool value) {
  m_IsAuthenticated = value;
}

正在回答您问题中有关 NUnit 如何工作的部分...

你引用的关于 NUnit 中夹具实例的生命周期的答案具有误导性,并且有点令人惊讶,因为它没有什么大的奥秘!

NUnit V2 的主要开发者 Jim Newkirk 的引述只是表达了他多么希望自己完成了 NUnit V2。他在 xUnit.net 框架中实现了这些想法,但它与 NUnit 3 无关。

NUnit 3 与 NUnit V2 一样,创建一个 TestFixture 实例,用于所有测试。您可以使用 [OneTimeSetUp] 创建要在测试中使用的对象并将它们存储为 class.If 的成员这些对象是有状态的,您应该避免对使用的夹具中的测试使用并行测试执行他们。

如果每个测试都需要额外的设置,那么您可以使用 [SetUp] 来达到这个目的,并使用 [TearDown] 删除任何会对后续测试产生负面影响的更改。

您还可以指定测试的顺序,但这通常不是一个好主意,因为一个失败的测试可能会导致后续测试也失败。如果可以,尽量让每个测试独立。

另请注意,如果您希望能够针对不同类型的对象多次 运行 相同的夹具,参数化夹具是一个不错的选择。只需将足够的信息传递给构造函数,以便在一次性设置中完成正确的对象初始化。

请务必阅读文档中上述所有内容的详细信息:https://github.com/nunit/docs/wiki