[英]UnitTests - Moq - How to Return() object from Moq that matches Parameter in Setup()
I am confused in Moq and I'm not sure what is wrong here. 我对起订量感到困惑,我不确定这里出了什么问题。
I would like to test LeadService that depend on ILeadStorageService, and I want to configure Moq in that way - Return the object that matches the GUID passed in Setup. 我想测试依赖ILeadStorageService的LeadService,我想以这种方式配置Moq-返回与安装程序中传递的GUID匹配的对象。
The problem is in the Moq Setup/Returns line, because when I substitute dependent object to its real instantiation - Test passes, but it is totally wrong. 问题出在Moq设置/返回行中,因为当我用依赖对象代替其实际实例时-测试通过,但这是完全错误的。 I don't want to test just LeadService, not a dependent storage.
我不想仅测试LeadService,而不要测试依赖存储。
public LeadService( IConfigurationDbContext configurationDbContext,
ILeadStorageService leadStorageService,
ILeadDeliveryService deliveryService)
{
this.configurationDbContext = configurationDbContext;
this.leadStorageService = leadStorageService;
this.deliveryService = deliveryService;
}
Tested method 测试方法
public TestLeadResponse ProcessTestLead(TestLeadRequest request)
{
var response = new TestLeadResponse()
{
Status = TestLeadStatus.Ok
};
try
{
var lead = leadStorageService.Get(request.LeadId);
if (lead == null)
{
throw new LeadNotFoundException(request.LeadId);
}
var buyerContract =
configurationDbContext.BuyerContracts.SingleOrDefault(bc => bc.Id == request.BuyerContractId);
if (buyerContract == null)
{
throw new BuyerContractNotFoundException(request.BuyerContractId);
}
response.DeliveryEntry = deliveryService.DeliverLead(lead, buyerContract);
}
catch (LeadNotFoundException e)
{
response.Status = TestLeadStatus.LeadNotFound;
response.StatusDescription = e.Message;
}
catch (BuyerContractNotFoundException e)
{
response.Status = TestLeadStatus.BuyerContractNotFound;
response.StatusDescription = e.Message;
}
return response;
}
then in test preparation: 然后在测试准备中:
[TestInitialize]
public void Initialize()
{
_leadIdStr = "2c3ac0c0-f0c2-4eb0-a55e-600ae3ada221";
_dbcontext = new ConfigurationDbContext();
_lead = PrepareLeadObject();
_buyerContract = PrepareBuyerContractObject(Id : 1, BuyerContractId : 1, BuyerTag: "GAME");
_leadDeliveryMock = new Mock<ILeadDeliveryService>();
_leadStorageMock = new Mock<ILeadStorageService>();
_leadStorageService = new LeadStorageService("LeadGeneration_Dev");
}
private Lead PrepareLeadObject()
{
var lead = new Lead() {CountryId = 1, Country = "NL", Id = Guid.Parse(_leadIdStr)};
return lead;
}
and the test itself: 和测试本身:
[TestMethod]
public void LeadServiceTest_ProcessTestLeadWithWrongBuyerContractIDThrowsBuyerContractNotFoundException()
{
_leadDeliveryMock
.Setup(methodCall => methodCall.DeliverLead(_lead, _buyerContract))
.Returns<LeadDeliveryEntry>((r) => PrepareLeadDeliveryEntry());
// here is the problem!!!!
_leadStorageMock.Setup(mc => mc.Get(_leadId)).Returns((Lead l) => PrepareLeadObject());
//if i change to real object - test passes
//_service = new LeadService(_dbcontext, _leadStorageService, _leadDeliveryMock.Object);
_service = new LeadService(_dbcontext, _leadStorageMock.Object, _leadDeliveryMock.Object);
var response = _service.ProcessTestLead(new TestLeadRequest() { BuyerContractId = int.MaxValue, LeadId = _leadId });
Assert.IsNotNull(response);
Assert.AreEqual(response.Status, TestLeadStatus.BuyerContractNotFound);
}
Instead of expected Return - I got an exception: 而不是预期的回报-我有一个例外:
What I am missing in _leadStorageMock.Setup().Returns() ? 我在_leadStorageMock.Setup()。Returns()中缺少什么?
The Returns
extension method accepts a delegate with same parameters as the method which you are mocking. Returns
扩展方法接受与您要模拟的方法具有相同参数的委托。 And those arguments will be passed to delegate during invocation of mocked method. 并且这些参数将在调用模拟方法期间传递给委托。 So instead of
Lead
object, you will get the argument which is passed to mc.Get
method - the lead id: 因此,您将获得传递给
mc.Get
方法的参数mc.Get
ID,而不是Lead
对象:
_leadStorageMock.Setup(mc => mc.Get(_leadId))
.Returns((Guid leadId) => PrepareLeadObject());
Check QuickStart section related to accessing invocation arguments when returning a value. 检查与返回值时访问调用参数有关的“ 快速入门”部分。
Note that there is a bunch of Returns
extension methods which accept a value function as an argument: 请注意,有一堆
Returns
扩展方法接受一个value函数作为参数:
Returns<T>(Func<T, TResult> valueFunction);
Returns<T1, T2>(Func<T1, T2, TResult> valueFunction);
Returns<T1, T2, T3>(Func<T1, T2, T3, TResult> valueFunction);
// etc
As you can see those value functions calculate the value to return from mocked method, but they all receive a different number of arguments (up to 16). 如您所见,这些值函数计算要从模拟方法返回的值,但是它们都接收不同数量的参数(最多16个)。 Those arguments will exactly match arguments of the method you are mocking and they will be passed to the
valueFunction
during invocation of the mocked method. 这些参数将完全匹配您要
valueFunction
的方法的参数,并且在调用valueFunction
期间会将它们传递给valueFunction
。 So if you are mocking some function with two arguments, then corresponding extension should be used: 因此,如果要模拟带有两个参数的某个函数,则应使用相应的扩展名:
mock.Setup(m => m.Activate(It.IsAny<int>(), It.IsAny<bool>())
.Returns((int i, bool b) => b ? i : 0); // Func<T1, T2, TResult>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.