[英]Moq an object created inside the method being tested
在下面的示例中,我想測試TestMe.DoSomething()
函數。
我想模擬此方法中使用的ISomething
接口,並使其返回不同的值(取決於特定的單元測試。)
在現實生活中, ISomething
接口逐漸呼喚昂貴的第三者資源-我絕對不想僅僅調用一個真正的ISomething
。
這是示例結構:
class TestMe
{
public void DoSomething()
{
ISomething s = SomethingFactory();
int i = s.Run();
//do things with i that I want to test
}
private ISomething SomethingFactory()
{
return new Something();
}
}
interface ISomething
{
int Run();
}
class Something : ISomething
{
public int Run()
{
return 1;
}
}
這是無效的代碼:
var fakeSomething = new Mock<ISomething>();
var testMe = new TestMe();
Mock.Get(testMe).Setup(p => p.SomethingFactory()).Returns(fakeSomething.Object);
testMe.DoSomething();
因為SomethingFactory()
是private
,所以我無法將該方法的返回值設置為所需的值。
關於如何解決這個問題有什么建議嗎?
使工廠成為完整的接口/類,並從TestMe中刪除SomethingFactory方法。
public interface ISomethingFactory {
ISomething MakeSomething();
}
public sealed class SomethingFactory {
public ISomething MakeSomething() {
return new Something();
}
}
class TestMe
{
private readonly ISomethingFactory _somethingFactory;
public TestMe(ISomethingFactory somethingFactory) {
_somethingFactory = somethingFactory;
}
public void DoSomething()
{
ISomething s = _somethingFactory.MakeSomething();
int i = s.Run();
//do things with i that I want to test
}
}
這將允許您模擬ISomethingFactory以返回ISomething的模擬。
盡管我認為您可能會反對這種解決方案,因為它太過激進了,但我認為它比制作一個沒有被成員密封的課程要好得多,后者的唯一原因是要進行虛擬測試。
您可以注入依賴項。 如果您不想破壞所有調用者,則可以添加兩個構造函數,並使用一個可以在測試中注入偽造的構造函數
class TestMe { private readonly ISomething something; TestMe() : this(new RealSomething() { } TestMe(ISomething sth) { something = sth; } public void DoSomething() { ISomething s = SomethingFactory(); int i = s.Run(); //do things with i that I want to test } private ISomething SomethingFactory() { return new Something(); } }
第二種方法是更改
SomethingFactory
保護虛擬並在派生類中重寫它並使用該類替代方法或進行設置的方法
class TestableTestMe : TestMe { private readonly ISomething something; TestableTestMe(ISomething testSpecific) { something = testSpecific; } public void DoSomething() { ISomething s = SomethingFactory(); int i = s.Run(); //do things with i that I want to test } protected override ISomething SomethingFactory() { return something; } }
此技術稱為“提取並覆蓋”
將SomethingFactory()更改為虛擬受保護,則可以使用Moq.Protected通過其名稱訪問該方法:
public class TestMe
{
public void DoSomething()
{
ISomething s = SomethingFactory();
int i = s.Run();
//do things with i that I want to test
}
protected virtual ISomething SomethingFactory()
{
return new Something();
}
}
public interface ISomething
{
int Run();
}
public class Something : ISomething
{
public int Run()
{
return 1;
}
}
因此,您可以運行以下測試:
var fakeSomething = new Mock<ISomething>();
fakeSomething.Setup(p => p.Run()).Returns(2);
var testMe = new Mock<TestMe>();
testMe.Protected().Setup<ISomething>("SomethingFactory").Returns(fakeSomething.Object);
testMe.Object.DoSomething();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.