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

时间:2015-05-06 18:17:06

标签: c# visual-studio-2012 mstest selenium-chromedriver

我正在使用Visual Studio 2012测试框架(我猜这是MSTest)。我有一些代码需要在运行各种testmethod之前运行一次。 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));
}

上面没有编译,因为在这个静态方法中正在新建类实例。但是我被迫使它变为静态,或者运行时错误导致“这必须是静态方法”和“错误签名”等。

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

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

如何做到这一点?

3 个答案:

答案 0 :(得分:3)

我不确定它是否真的是最佳方法,但您可以将其设为静态变量 - 从实例方法访问静态变量很方便(你的测试)毕竟。

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

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

答案 1 :(得分:0)

假设您的测试类包含10个测试。为了进行适当的测试,您的测试不应受其他测试的影响,您的测试也不应影响其他测试。

为了强制执行此操作,单元测试的开发人员定义每个测试都在其自己的测试类对象中运行。这使您可以自由地更改测试类对象中的变量,而不会影响其他测试。

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

但是,如果您不想使用静态变量,请考虑使用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()。

答案 2 :(得分:0)

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

    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
    }