c# - 这是错误的起订量设置还是起订量不足?

标签 c# moq

我正在尝试测试以下代码:

public async Task<Activity> Get(long ID, Recruiter User, bool IsArchived = false)
{
    Activity result = await collection.FirstOrDefault(x => x.ID == ID && x.Recruiter.CompanyID == User.CompanyID && (!x.Archived || IsArchived));
    return result;
}

通过以下测试:

[TestMethod]
public async Task GetDoesThings()
{
    long ID = 1;
    bool IsArchived = false;
    Recruiter User = new Recruiter()
    {
        CompanyID = 1
    }; 

    ActivitiesMock.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))).ReturnsAsync(new Activity());

    Activity result = await repo.Get(ID, User);

    ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));
}

(我知道有不同的写法,这是我们最近尝试的迭代。)

ActivitiesMockcollection 有关在 Get(long ID, Recruiter User, bool IsArchived = false) 中找到.我们最近编写了包装器,以便更有效地尝试和测试我们的实体调用,但是在尝试验证调用是否正确时,我们遇到了这个错误:

Test method ExampleProject.Tests.Backend.Repositories.ActivityRepositoryTests.GetDoesThings threw exception: Moq.MockException: Expected invocation on the mock at least once, but was never performed: x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived))

Configured setups: x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived)), Times.Never

Performed invocations: IAppCollection`2.FirstOrDefault(x => (((x.ID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).ID) AndAlso (x.Recruiter.CompanyID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).User.CompanyID)) AndAlso (Not(x.Archived) OrElse value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).IsArchived)))

在此实例中,包装器 ( collection ) 是接口(interface)的模拟。目标是确保存储库在包装器上调用正确的表达式,以便我们知道传递给实体 DbSet 的谓词是正确的,而不必担心所有困惑的异步抽象。

模拟 Setup()运行测试时,以及当我更改 Setup() 时,似乎没有找到完整谓词至 It.IsAny<Expression<Func<Activity, bool>>>()它运行模拟并提供返回,但是 Verify通话不起作用。所以,运行:

ActivitiesMock.Setup(x => x.FirstOrDefault(It.IsAny<Expression<Func<Activity, bool>>>())).ReturnsAsync(new Activity());

Activity result = await repo.Get(ID, User);

Assert.IsNotNull(result);
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));

通过断言但未通过验证,同时运行:

ActivitiesMock
    .Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)))
    .ReturnsAsync(new Activity())
    .Verifiable();

Activity result = await repo.Get(ID, User);

Assert.IsNotNull(result);
ActivitiesMock.Verify();

断言失败。

看起来它失败了,因为它需要相同的对象类型。我是在尝试做一些 Moq 无法处理的事情,还是我错过了一些我需要做的事情才能使验证正确?

根据要求,LINQ-to-Entity 包装器 (collection) 的具体实现是:

public Task<T> FirstOrDefault(Expression<Func<T, bool>> Predicate)
{
    return DbSet.FirstOrDefaultAsync(Predicate);
}

虽然包装器本身没有被使用,但是它的一个接口(interface)正在被模拟,我们正在测试的就是那个模拟。

最佳答案

答案都不是。由于匿名函数必须创建类实例来存储所提供的数据,因此它们会创建 DisplayClass 实例来保存数据。由于这些实例是在不同的命名空间中创建的(除其他外),当 Moq 对它们调用 .Equals 时,它们不会通过。

我们通过这样编写测试解决了这个问题:

ActivitiesMock
    .Setup(x => x.Where(It.IsAny<Expression<Func<Activity, bool>>>()))
    .Returns((Expression<Func<Activity, bool>> x) =>
    {
        actualPredicate = x;
        return queryMock.Object;
    });

然后创建有效和无效事件以提供给谓词以确保它正确返回 truefalse:

Assert.IsTrue(actualPredicate.Compile().Invoke(validActivity));

现在承认它有点 hacky,但乍一看它似乎不太像垃圾箱火灾解决方案,这是我们确保提供的调用按照我们期望的方式进行的一种方式,这就是我们想要。

更新(2016 年 9 月 7 日):到目前为止,这对我们来说效果很好。我们遇到了 LINQ-to-Entity 语句未按预期运行的问题,因为 LINQ 区分大小写而生成的 SQL 不区分大小写,但由于这对我们来说不是一个交易破坏者,我们只是很好。

关于c# - 这是错误的起订量设置还是起订量不足?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38015326/

相关文章:

c# - 我使用rigidbody2D.velocity.y时出现语法错误

c# - 为什么 EPPlus 告诉我 "Can' t set color when patterntype is not set"当我设置了 PatternType 时?

c# - 如何从 .NET MVC Controller 测试 JsonResult

c# - 测试异步方法时如何使用序列?

c# - 我怎样才能模拟这个静态方法

C# 复制字符串的子串,然后将其放在字符串的下一个单词之前

javascript - 执行了 ajax 请求。如何格式化返回的数据?

c# - C# SortedList<TKey, TValue>.Keys.Contains 方法抛出 null 异常是一件好事吗?

unit-testing - 将 Generic.List 转换为 System.Threading.Task.Generic.List 时出现问题

c# - 每次使用 Moq 调用方法时,如何使 Mock 返回一个新列表