我遇到了一些MSTest单元测试的麻烦,当我单独运行它们时会通过,但是当我运行整个单元测试类时会失败。测试测试了SLaks helped me with earlier的一些代码,他警告我,我在做什么不是线程安全的。但是,现在我的代码更复杂,我不知道如何使其成为线程安全的。这就是我所拥有的:
public static class DLLConfig
{
private static string _domain;
public static string Domain
{
get
{
return _domain = AlwaysReadFromFile
? readCredentialFromFile(DOMAIN_TAG)
: _domain ?? readCredentialFromFile(DOMAIN_TAG);
}
}
}
我的测试很简单:
string expected = "the value I know exists in the file";
string actual = DLLConfig.Domain;
Assert.AreEqual(expected, actual);
当我自己运行此测试时,它会通过。当我将它与测试类中的所有其他测试(在不同属性上执行类似检查)一起运行时,actual
为null
并且测试失败。我注意到,对于类型为自定义Enum
类型的属性,这不是问题。也许我对Domain
属性有这个问题,因为它是string
?或者这可能是MSTest如何工作的多线程问题?
答案 0 :(得分:6)
我怀疑其他测试正在修改DLLConfig
类中导致getter结果发生变化的一些值。单元测试应该始终从已知的初始状态运行,因此您应该在测试方法本身或在每次测试之前运行的TestInitialize
属性标记的方法中设置它。
答案 1 :(得分:5)
您的测试取决于外部文件。而不是调用直接访问该文件的函数,您应该让DLLConfig.Domain调用另一个类中的方法。
public static string Domain
{
get
{
return _domain = AlwaysReadFromFile
? CredentialReader.Read(DOMAIN_TAG)
: _domain ?? CredentialReader.Read(DOMAIN_TAG);
}
}
然后,您可以使用mock / fake / stub CredentialReader初始化DllConfig,您可以在其中控制其返回值。请记住,您正在测试DLLConfig.Domain是否根据AlwaysReadFromFile
条件返回正确的值。您不应该同时测试该值的来源(或者甚至是否存在)。
让您的DLLConfig类更“可测试”,可以分离出各种问题。当你想到一个课时,不禁要说“这个课 AND 那个”(抽象配置数据并阅读来自文件的数据)这是一个很好的选择,该课程正在混合关注并试图做很多事情。如果DLLConfig是配置数据的抽象,那么它应该只关注它并将数据从哪里留到另一个类。
答案 2 :(得分:1)
如果上述答案都不适合您,我通过在失败测试中断言之前添加Thread.Sleep(1)
来解决此问题...
看起来在某处错过了测试同步...请注意我的测试不依赖于顺序,我没有任何静态成员也没有外部依赖。
答案 3 :(得分:0)
对我来说,问题在于使用了非线程安全的集合。当我切换到使用BlockingCollection(而不是List)时,一切都变得正确了。