由于不了解此方案的技术名称,我深表歉意。我在嘲笑单元测试,这一切都很好。但是在这部分代码中,我遇到了一个超出我嘲弄知识的场景。基本上我有MethodA,它有3个参数。其中一个参数作为另一个方法的输出传递。
当我逐步执行作为参数传递的方法时
我的困难在于,在我的模拟对象之前正在执行传递的方法。现在它似乎是一个简单的解决方案......嘲笑第二种方法......这就是我的知识落空的地方。我不知道如何将“第二”方法模拟到测试环境中。
我的控制器正在测试(当然简化):
public class OrderController : ApiController
{
public OrderController(IRepositoryK repositoryk)
{}
public HttpResponseMessage NewOrder()
{
...snip....
string x = repositoryk.MethodA("stuff", "moreStuff", MethodB("junk"));
}
public string MethodB(string data)
{
using (var client = new HttpClient())
{...make call to Google API...}
}
}
我的测试:
[TestMethod]
public void AddOrder_CorrectResponse()
{
private Mock<IRepositoryK> _repK = new Mock<IRepositoryK>();
_repK.Setup(x => x.MethodA(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns("Yippe");
//of course I've left out all the controller buildup and execution stuff.
}
所以我真的不想潜入MethodB,但无论如何它似乎都在做。我做错了什么?
TIA
感谢您的回复。我完全理解你在说什么。我正在尝试在重构之前获得一些测试覆盖率。那么有没有办法让methodB不执行,只是让我的repositoryK mock返回我在设置中指定的内容。
答案 0 :(得分:2)
您的代码不容易测试,因为它对HttpClient有很强的依赖性。您已经很好地分离了存储库实现,但如果您想轻松测试代码,您还应该将调用Google API的代码分开。我的想法是这样的:
// Add interfece for accessing Google API
public interface IGoogleClient
{
string GetData(string data);
}
// Then implementation is identical to MethodB implementation:
public class GoogleClient : IGoogleClient
{
public string GetData(string data)
{
using (var client = new HttpClient())
{
//...make call to Google API...
}
}
}
// Your controller should look like this:
public class OrderController : ApiController
{
private readonly IRepositoryK repositoryk;
private readonly IGoogleClient googleClient;
public OrderController(IRepositoryK repositoryk, IGoogleClient googleClient)
{
this.googleClient = googleClient;
this.repositoryk = repositoryk;
}
public HttpResponseMessage NewOrder()
{
//...snip....
string x = repositoryk.MethodA("stuff", "moreStuff", MethodB("junk"));
}
public string MethodB(string data)
{
return googleClient.GetData(data);
}
}
如果您有此类设置,则可以轻松模拟IRepositoryK
和IGoogleClient
:
Mock<IRepositoryK> repK = new Mock<IRepositoryK>();
Mock<IGoogleClient> googleClient = new Mock<IGoogleClient>();
repK.Setup(x => x.MethodA(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("Yippe");
googleClient.Setup(It.IsAny<string>()).Returns("something");
var controller = new OrderController(repK.Object, googleClient.Object);
// Test what you want on controller object
但是,如果您希望保持代码紧密耦合,则可以通过较小的更改来模拟对MethodB
的调用。
首先,您需要将方法MethodB
设为虚拟,因此可以在模拟中重写:
public virtual string MethodB(string data)
{
// your code
}
然后在您的测试中,而不是实例化控制器,实例化并使用控制器的模拟:
var repK = new Mock<IRepositoryK>();
// create mock and pass the same constructor parameters as actual object
var controllerMock = new Mock<OrderController>(repK.Object);
controllerMock.CallBase = true;
// mock MethodB method:
controllerMock.Setup(x => x.MethodB(It.IsAny<string>())).Returns("data");
// call the method on mock object
// instead of calling MethodB you will get a mocked result
var result = controllerMock.Object.NewOrder();