[英]Unit test by mocking external DLL using Moq in C#
我正在嘗試為我的一個函數編寫一個單元測試,該函數依賴於外部 DLL。 我決定使用 Moq(模擬外部依賴)來測試我的 function。
MyClass 有一個 function 和一個外部依賴項。
namespace MyService
{
/// <summary>
/// MyClass
/// </summary>
public class MyClass : IMyClass
{
private ExternalClass ex;
public MyClass() {
ex = new ExternalClass();
}
public bool publish(string param) {
if(... param is not valid)
throw error;
return ex.externalPublish(param);
}
}
}
外部 class 發布 function 調用一些運行時依賴項,因此不能期望 function 在單元測試期間運行
namespace ExternalService
{
/// <summary>
/// ExternalClass
/// </summary>
public class ExternalClass : IExternalClass, OtherExternalClass // OtherExternalClass is a concrete one, not an interface
{
public ExternalClass(){}
public bool publish(string param) {
// some implementation which contacts database, other running services etc.
}
}
}
namespace MyServiceTests
{
using Moq;
/// <summary>
/// MyClass test
/// </summary>
[TestClass]
public class MyClassTest
{
/// <summary>
/// Publish
/// </summary>
[TestMethod]
public void PublishTestSucceed()
{
var moq = new Mock<ExternalClass>(); // I tried IExternalClass but it is not the only inheritence that ExternalClass has.
moq.CallBase = true;
moq.Setup(tsmv2 => tsmv2.publish(
It.IsAny<string>()))
.Returns(true);
MyClass myC = new MyClass();
PrivateObject obj = new PrivateObject(myC);
obj.SetField("ex", moq.Object); // If I use IExternalClass to create moq, I am not able to convert IExternalClass to ExternalClass here.
bool result = myC.publish("asdf");
Assert.IsTrue(result);
}
所以有兩個問題:
moq.Object
轉換為 IExternalClass object,即使使用顯式轉換也是如此。被測對象與具體的外部實現細節緊密耦合,並且應該依賴於通過構造函數注入使用顯式依賴原則的抽象。
重構主題 class:
public class MyClass : IMyClass {
private IExternalClass ex;
public MyClass(IExternalClass ex) {
this.ex = ex;
}
public bool publish(string param) {
if(... param is not valid)
throw error;
return ex.publish(param); //... external call
}
}
對於主題 class 來說,依賴關系是外部的,這真的無關緊要。 那是一個實現細節。
現在,這允許主題 class 明確說明執行其 function 所需的內容,並且通過依賴抽象允許使用替代品。 例如,在隔離測試時。
[TestClass]
public class MyClassTest {
public void PublishTestSucceed() {
// Arrange
var dependency = new Mock<IExternalClass>();
dependency
.Setup(_ => _.publish(It.IsAny<string>()))
.Returns(true);
MyClass myC = new MyClass(dependency.Object);
//Act
bool result = myC.publish("asdf");
//Assert
Assert.IsTrue(result);
}
}
如果顯式使用IExternalClass
作為依賴項有太多限制,請考慮使用封裝/包裝外部依賴項功能的實現創建自己的抽象。
這樣您就可以更好地控制您的代碼,並且不受您無法控制的依賴項限制的限制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.