該測試應該是:1)可讀性,2)易於編寫/維護。 「可讀」是什麼意思?這意味着它最大限度地減少了跳過代碼的次數,以瞭解特定代碼行上正在做什麼。
考慮創建測試項目中的工廠。我認爲這是爲測試安排是可讀的最好的方法之一:
public static class MyClassFactory
{
public static MyClass Create(ISomeService serviceA, ISomeOtherService serviceB)
{
return new MyClass(serviceA, serviceB);
}
public static MyClass CreateEmpty()
{
return new MyClass();
}
//Just an example, but in general not really recommended.
//May be acceptable for simple projects, but for large ones
//remembering what does "Default" mean is an unnecessary burden
//and it somehow reduces readability.
public static MyClass CreateWithDefaultServices()
{
return new MyClass(/*...*/);
}
//...
}
(第二個選項將在後面解釋)。然後你可以使用這樣的:它
[TestMethod]
public void it_should_do_something()
{
//Arrange
var myClass = MyClassFactory.Create(serviceA, serviceB);
//Act
myClass.DoSomething();
//Assert
//...
}
注意如何提高可讀性。除了serviceA
和serviceB
,我只留下符合你的榜樣,你需要了解的一切就是在這條線上。理想情況下,它看起來像這樣:
[TestMethod]
public void it_should_do_something()
{
//Arrange
var myClass = MyClassFactory.Create(
MyServiceFactory.CreateStubWithTemperature(45),
MyOtherServiceFactory.CreateStubWithContents("test string"));
//Act
myClass.DoSomething();
//Assert
//...
}
這提高了可讀性。請注意,即使DRY的設置已結束,所有工廠方法都很簡單明瞭。沒有必要查看他們的定義 - 他們從一見鍾情清楚。
可以緩解寫作和維護得到進一步提高?
一個很酷的想法是提供您的測試項目中的擴展方法MyClass
允許可讀的配置:
public static MyClassTestExtensions
{
public static MyClass WithService(
this MyClass @this,
ISomeService service)
{
@this.SomeService = service; //or something like this
return @this;
}
public static MyClass WithOtherService(
this MyClass @this,
ISomeOtherService service)
{
@this.SomeOtherService = service; //or something like this
return @this;
}
}
那麼你當然像這樣使用:
[TestMethod]
public void it_should_do_something()
{
//Arrange
var serviceA = MyServiceFactory.CreateStubWithTemperature(45);
var serviceB = MyOtherServiceFactory.CreateStubWithContents("test string");
var myClass = MyClassFactory
.CreateEmpty()
.WithService(serviceA)
.WithOtherService(serviceB);
//Act
myClass.DoSomething();
//Assert
//...
}
當然中服務不是這種配置的一個好例子(通常,沒有它們的對象是不可用的,所以沒有提供默認的構造函數),但是對於它提供的任何其他屬性一個巨大的優勢:使用N個屬性進行配置,您可以維護一個乾淨可讀的方式,使用N個擴展方法創建所有可能的配置的測試對象,而不是N x N個工廠方法,並且在構造函數或工廠方法調用中沒有N長參數列表。
如果你的類不像上面假設的那麼方便,一種可能的解決方案是對它進行子類化,併爲子類定義工廠和擴展。
如果它沒有意義爲對象與它的屬性中的一部分存在,他們不能設定你能流利地配置一個工廠,然後創建對象:
//serviceA and serviceB creation
var myClass = MyClassFactory
.WithServiceA(serviceA)
.WithServiceB(serviceB)
.CreateMyClass();
我希望這種工廠的代碼很容易推斷,所以我不會寫在這裏,因爲這個答案已經看起來有點長了)
我使用TestInitialize的方式,你給第二。正是出於這個原因。我相信如果您的單元測試課程集中並且只測試'一件事'(沒有蔓延),那麼這種方式可以使測試變得很好並且乾淨,並且'設置'會被排除在外。我不認爲可讀性會受到這種干擾。 – CodeBeard