[英]Unit testing a method that uses an external dll
我有一個名為A的項目,它有一個名為ClassA的類。 ClassA有一個名為ReadBlock()的方法,它創建一個CloudBlockBlob對象並調用其中一個方法。
CloudBlockBlob是一個位於Microsoft.WindowsAzure.Szrage.Blob命名空間的類,該命名空間位於Microsoft.WindowsAzure.Storage.dll中 。
我的項目A有一個名為A.Tests的單元測試項目。 現在,我想測試方法ReadBlock() 。 為了測試它,我需要模擬CloudBlockBlob對象並攔截對其方法的調用,返回自定義值並驗證方法是否被調用。
更新:問題是我是否可以在不修改項目A的代碼的情況下完成此操作。
謝謝!
如果不修改A
類代碼,您將無法使用Moq來修改ReadBlock
方法。 您將能夠使用代碼編織工具(MsFakes,Typemock隔離器等)來使用此方法。
例如(MsFakes):
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
ShimCloudBlockBlob.AllInstances.<the method you want to override> = (<the method arguments>) => {};
}
}
在using
范圍內,您將能夠通過屬性AllInstances
覆蓋CloudBlockBlob具有的任何方法。
在下一節中,我將討論你擁有的所有其他選項......
選項1:
public class A
{
private IBlockBlob _blockBlob;
public A(IBlockBlob blockBlob)
{
_blockBlob = blockBlob;
}
public void ReadBlock()
{
_blockBlob.DoSomething();
}
}
由於每次調用ReadBlock
(您的方法的當前行為)時都會創建一個新實例,因此最好注入工廠而不是包裝器,並且應該create
DoSomething
; 選項2:
public class A
{
private readonly IFactoryBlockBlob _blobFctory;
public A(IFactoryBlockBlob blobFctory)
{
_blobFctory = blobFctory;
}
public void ReadBlock()
{
var blob = _blobFctory.Create();
}
}
但是,根據您的問題和您的評論,您的班級似乎“有依賴”而不是“需要依賴”。
(馬克西門子寫了一本關於DI的好書,這張圖取自他的書 )
有了這條新信息,您的方法應該是這樣的; 選項3:
public class A
{
public void ReadBlock(ICloudBlob blob)
{
}
}
但是你不想改變方法的簽名:
public class A
{
public void ReadBlock()
{
ReadBlock(new CloudBlockBlob(<the params bla bla...>));
}
internal void ReadBlock(ICloudBlob blob)
{
}
}
添加InternalsVisibleToAttribute
,然后驗證內部方法的行為。
通過閱讀這些內容,我覺得您的課程是一種“遺留代碼”,意味着它可以完成工作,不會改變,並且驗證其行為可能是浪費時間。 在過去,我發布了一個圖表( 在這個答案中 ),可以幫助您決定處理此案例的方法。
最好為CloudBlockBlob創建一個非常簡單的可模擬包裝器,以提高代碼的可測試性並使用依賴性反轉注入它。
現在你可能有類似的東西:
public class A
{
public void ReadBlock()
{
var blockBlob = new CloudBlockBlob();
blockBlob.DoSomething();
}
}
相反,將您的包裝器注入A中,以便A不知道對CloudBlockBlob的依賴:
public class A
{
IBlockBlob _blockBlob
public A(IBlockBlob blockBlob)
{
_blockBlob = blockBlob;
}
public void ReadBlock()
{
_blockBlob.DoSomething();
}
}
免責聲明,我在Typemock工作。
您可以在不使用Isolator修改項目A代碼的情況下執行此操作。 有一個簡單的例子如何完成:
public class Foo
{
public void ReadBlock()
{
var block = new CloudBlockBlob(new Uri("http://myUrl/%2E%2E/%2E%2E"));
var name = block.Name;
}
}
[TestMethod, Isolated]
public void TestReadBlock()
{
//Arrange
var fakeBlock = Isolate.Fake.AllInstances<CloudBlockBlob>();
Isolate.WhenCalled(() => fakeBlock.Name).WillReturn("Name");
//Act
var foo = new Foo();
foo.ReadBlock();
//Assert
Isolate.Verify.WasCalledWithAnyArguments(() => fakeBlock.Name);
}
希望能幫助到你!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.