MSTest 中是否有非静态 ClassInitialize 替代方案?

Is there a non-static ClassInitialize alternative in MSTest?

我正在使用 Visual Studio 2012 测试框架(我想那是 MSTest)。在各种测试方法 运行 之前,我有一些代码需要 运行 并且只需要一次 。 ClassInitialize 看起来很完美,直到我了解到它必须是静态的。

首先,我有一个 ChromeDriver:

的实例变量
private ChromeDriver driver;

我想我需要这样的东西,但不是静态的:

[ClassInitialize]
public static void Initialize() {
    ChromeOptions options = new ChromeOptions();
    options.AddArgument("test-type");
    options.AddArgument("start-maximized");
    options.LeaveBrowserRunning = true;
    driver = new ChromeDriver(@"C:\MyStuff", options);
    driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(4));
}

上面的代码无法编译,因为 class 个实例正在这个静态方法中更新。但我不得不将其设置为静态,或者 运行 时间错误导致 "this has to be a static method" 和 "wrong signature" 等

如果我在 class 构造函数或 TestInitialize 方法中启动我的 Chrome 驱动程序(声明为 class 变量),一切正常,但是 一个新的浏览器 window 为每个测试打开 。因此,当我有 50 个测试方法时,我将打开 50 个 Chrome 实例,这很糟糕。

我只想为每个测试重用我的 driver 实例,而不必每次都启动一个新实例,这会打开一个新浏览器。

如何做到这一点?

我不确定它是否真的是 最佳 方法,但您可以将其设为静态变量 - 可以在之后从实例方法(您的测试)访问静态变量全部.

请注意,如果您尝试 运行 并行测试,这可能会导致问题。可能值得研究测试实例生命周期是什么 - 您可以在其中使用一个 实例 进行多个测试,在这种情况下,在构造函数中初始化实例变量可能是另一种合理的方法。

(除非初始化驱动程序真的需要很长时间,否则我很想在每次测试的基础上创建它...)

假设您的测试 class 包含 10 个测试。为了一个正确的测试,你的测试不应该受到其他测试的影响,你的测试也不应该影响其他人。

为了加强这一点,单元测试的开发人员定义了每个测试 运行 在它自己的测试 class 对象中。这使您可以自由更改测试 class 对象中的变量,而不会影响其他测试。

您希望您的初始化程序仅 运行 一次,并且所有测试都使用相同的变量。每个测试 运行s 在它自己的测试对象中,因此这些变量必须是共同的。最简单的方法是静态变量。

但是,如果您不想使用静态变量,请考虑使用 the singleton design pattern。唯一的单例对象包含您要在任何测试开始之前初始化的变量。

private class MySingleton
{
    public static MySingleTon GetInstance()
    {
        if (theOneAndOnlyInstance == null)
        {
            theOneAndOnlyInstance = new MySingleton(...);
        }
        return theOneAndOnlyInstance;
    }

    private static MySingleton theOneAndOnlyInstance = null;

    private MySingleton(...)
    {
        ... // initialize the non-static test variables
    }

    #region test variables
    public int TestVariableX {get; set;}
    ...
    #endregion test variables
}

[TestMethod}
public void MyTest()
{
    var myTestVariables = MySingleton.GetInstance(); 
    ...
}

优点是测试变量在任何人使用之前都不会创建或初始化。构造函数是私有的,因此唯一可以创建对象的是静态函数 GetInstance()。

我不确定这是否是最佳方法,但似乎可行。 您在这里唯一需要的是唯一的测试方法名称部分。

    private const string TEST_METHOD_UNIQUE_NAME_PART = "test";
    private static TestContext _testContext;
    private static bool _isPreconditionCompleted;
    private static int _numberOfCompletedTests;

    private int NumberOfTestMethodsInClass
    {
        get
        {
            var className = _testContext.FullyQualifiedTestClassName.Split('.').Last().Trim();
            var currentType = Assembly.GetExecutingAssembly().GetExportedTypes()
                             .Where(r => r.Name.Trim() == className).First();

            return currentType.GetMethods().Where(r => r.Name.ToLower()
                  .Contains(TEST_METHOD_UNIQUE_NAME_PART)).Count();
        }
    }

    [ClassInitialize]
    public static void ClassSetUp(TestContext testContext)
    {
        _testContext = testContext;
        _isPreconditionCompleted = false;
        _numberOfCompletedTests = 0;
    }

    [TestInitialize]
    public void SetUp()
    {
        if (!_isPreconditionCompleted)
        {
            PreConditionMethod();
        }
    }

    [TestCleanup]
    public void TearDown()
    {
        _numberOfCompletedTests++;

        if (_numberOfCompletedTests == NumberOfTestMethodsInClass)
        {
            PostConditionMethod();
        }
    }

    private void PreConditionMethod()
    {
        // Your code
        _isPreconditionCompleted = true;
    }

    private void PostConditionMethod()
    {
        // Your code
    }