[英]Different Garbage Collection behavior between Console Application and Unit Test Method
[英]Unit Test Garbage Collection
題
一旦測試完成,單元測試是否通過垃圾收集(在我的情況下為System.IO.Stream
)自動處理資源,或者是否處於打開/正在使用狀態,需要處理IDisposable
對象?
背景/信息
我目前正在為使用System.IO.Stream
的文件上傳器進行單元測試。
我Moq'd了HttpPostedFileBase
與搭載了該文件的InputStream的System.IO.MemoryStream
,而這一切按預期工作。
我目前有(為簡潔起見):
[TestMethod]
public void TestUpload()
{
var stream = FunctionCreatingTheMemoryStream();
try
{
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
finally
{
stream.Dispose();
}
}
問題是創建的MemoryStream
實例:
var stream = new FunctionCreatingTheMemoryStream();
是否值得在try catch
之后放置任何代碼,然后在finally
語句中處理流,或者作為單元測試,是否會自動處理內存流?
所以有必要這樣做,或者它可能只是:
[TestMethod]
public void TestUpload()
{
var stream = FunctionCreatingTheMemoryStream();
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
答案最終取決於您使用的單元測試框架,但在.NET中,三個主要測試框架(MSTest,NUnit,xUnit.net)都沒有自動處理。 您必須手動要求他們這樣做。
你可以說,在執行測試套件時,測試運行器原則上啟動一個新進程,運行所有測試,然后進程退出。
對於IDisposable
某些實現,如MemoryStream
,這只是意味着在進程退出時回收內存。 但是,您不能總是依賴它,因為某些一次性類型可能會訪問進程外資源。 理論上,您可以將對象保存到內存映射文件,命名管道,SQL Server連接等。即使測試進程退出,您也可能留下這些資源。 它們可能遲早會超時(比如SQL Server連接返回池中),但它可能會降低系統速度。
此外,一些測試運行者現在非常努力變得聰明,因此他們重用一個或多個進程以便能夠更快地運行,從而更改您的測試套件進出AppDomains。
所以,最后,除非你有像MemoryStream
這樣的東西,你絕對肯定將它留下來並不是什么大不了的事,你應該在測試中確定地處理你的對象。
但是,如果您正在進行測試驅動開發,那么您應該采用GOOS的態度來傾聽您的測試 。 如果您編寫了許多涉及IDisposable對象的測試,您應該考慮是否可以簡化SUT的API。 這取決於你正在做什么,但如果你寫的主要是托管代碼,你不應該使用IDisposable
,因為它是泄漏SUT依賴於非托管資源的漏洞抽象 。
在過去,我編寫了一個實現IDisposable的“Dustcart”類,並包含要處理的對象集合。 它們按操作順序排列,以便添加它們(使用堆棧來實現它)。
然后測試代碼看起來像。
[Setup]
Public void Setup()
{
_dustcart = new Dustcart()
}
[TearDown]
public void TearDown ()
{
_dustcart.Dispose();
}
[TestMethod]
public void TestUpload()
{
var stream = _dustcart.DisposeOnTearDown(FunctionCreatingTheMemoryStream());
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
DisposeOnTearDown()
是一種通用方法。 你可以把它放在一個超級類中,你所有的測試都是固有的,也包括那些你需要模擬的類的母親 。
但是,如果您不是非常小心,您的測試代碼將變得難以理解,而您正在測試的軟件質量沒有任何實際好處。 這些測試是為了完成一項工作而且他們必須要比完成這項工作所需要的更好。
完全同意每個人你需要處理這些對象。 您可以使用“using”語句簡化代碼,如下所示:
[TestMethod]
public void TestUpload()
{
using (var stream = FunctionCreatingTheMemoryStream())
{
var file = new Mock<HttpPostedFileBase>();
file.Setup(f => f.FileName).Returns("test.txt");
file.Setup(f => f.InputStream).Returns(stream);
MethodThatUsesTheStream(file.Object)
// rest of test code with Assert
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.