【问题标题】:Mocking generic methods in Moq with interface使用接口模拟 Moq 中的泛型方法
【发布时间】:2019-02-11 19:03:05
【问题描述】:

我正在尝试为以下通用接口设置最小起订量,但出现异常

 public interface IReadAccess<TEntity>
 {
     Task<IEnumerable<TEntity>> GetAll();
 }

var m = new Mock<IReadAccess<Foo>>(MockBehavior.Strict);

m.Setup(p => p.GetAll()).ReturnsAsync(new List<Foo>());

m.VerifyAll();

得到以下异常

Moq.MockException
  HResult=0x80131500
  Message=The following setups on mock
    'Mock<EPIC.CrossCutting.Interfaces.DAL.Framework.IReadAccess<EPIC.CrossCutting.DTOs.Data.Announcement.AnnouncementCrosscutDTO>:00000002>' 
  were not matched:
IReadAccess<AnnouncementCrosscutDTO> p => p.GetAll()

  Source=Moq
  StackTrace:
   at Moq.Mock.VerifyAll()
   at EPIC.Tests.Business.Rules.Announcements.AnnouncementPlanning.CrosscutsProgrammaticActivitiesValidationRuleServiceTests.<ExecuteSuccessTest>d__5.MoveNext() 
in D:\dev\main\Tests\EPIC.Tests.Business.Rules\Announcements\AnnouncementPlanning\CrosscutsProgrammaticActivitiesValidationRuleServiceTests.cs:line 108

【问题讨论】:

  • 你能修复你的代码 sn-p 以便我们可以看到你的模拟是如何设置的吗?
  • SetupVerifyAll 之间是否有一些代码实际上调用了GetAll 方法?
  • 请阅读minimal reproducible example 指导和edit 帖子以显示匹配并重现您的错误消息的代码。目前的代码显然是一些不会导致错误显示的简化。

标签: c# unit-testing moq


【解决方案1】:

您的测试正确失败,因为您尝试验证 GetAll() 是否已被调用,即使您实际上并未调用它。

如果您在测试或您正在测试的代码中调用该方法,它将通过。

[Fact]
public async Task Test1()
{
    var m = new Mock<IReadAccess<Foo>>(MockBehavior.Strict);
    m.Setup(p => p.GetAll()).ReturnsAsync(new List<Foo>());

    var result = await m.Object.GetAll();

    m.VerifyAll();
}

线索在您的错误消息中: Message=Mock .... 上的以下设置不匹配: IReadAccess p => p.GetAll()

【讨论】:

  • 谢谢康奈尔,这是预期的工作,但我有类似的方法 public interface IReadAccess { Task> GetAll(); }
【解决方案2】:

感谢康奈尔,这是预期的工作,但我有类似的方法

public interface IReadAccess<TEntity>  
{  
    Task<IEnumerable<TEntity>> GetAll();   
    Task<IEnumerable<TEntity>> Find(FormattableString whereClause, object whereClauseObject);

} 

并尝试设置

var m = new Mock<IReadAccess<Foo>>(MockBehavior.Strict);
m.Setup(x => x.Find($"ID = @ID", new { ID = 5 })).ReturnsAsync(new List<Foo>());
var result = await m.Object.Find($"ID= @ID", new { ID = 5 });
m.VerifyAll();

在对现有代码进行了一些更改后,现在设置工作正常,但在从测试调用实际服务时出现错误,更新代码

var test = new Test {ID = 5};
object whereClause = new { ID = test.ID };
            FormattableString formattableString = $"ID = @ID";

            m.Setup(x => x.Find(formattableString, whereClause)).ReturnsAsync(new List<Foo>());

 var ruleServiceOutput = await this.testValidationRuleService.ExecuteAsync(test);

实际代码

public async Task<IRuleServiceOutput<bool>> ExecuteAsync(Test test)
        {
            var errors = new List<string>();

            object whereClause = new { ID = test.ID };
            FormattableString formattableString = $"ID = @ID";

            var output = (await m.Find(formattableString, whereClause)).ToArray();

            return new RuleServiceOutput<bool>(output.Errors.IsEmpty(), output.Errors);
        }

'IReadAccess`1.Find(ID = @ID, { ID = 5 }) 调用失败,模拟行为严格。 模拟上的所有调用都必须有相应的设置。'

设置 MockBehavior.Default 后一切正常:)

【讨论】:

  • 尝试像这样设置模拟m.Setup(x =&gt; x.Find(It.IsAny&lt;FormattableString&gt;(), It.IsAny&lt;object&gt;())).ReturnsAsync(new List&lt;Foo&gt;());
猜你喜欢
  • 1970-01-01
  • 2016-06-06
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-22
  • 2017-03-13
相关资源
最近更新 更多