如何使用 FakeItEasy 验证 FindOneAndUpdateAsync 方法 运行 以对抗伪造的 MongoCollection?

How to use FakeItEasy to verify FindOneAndUpdateAsync method ran Against faked MongoCollection?

我正在使用 FakeItEasy 库进行单元测试,并尝试为 mongo 更新语句编写单元测试,并验证是否使用 [=17] 调用了 FindOneAndUpdateAsync 方法=].

我创建了一个单元测试,它将伪造 dbcontext class,使用它来生成 collection,然后调用将 运行 更新的方法声明反对造假collection。当我在调试模式下 运行 测试时,它命中了 FindOneAndUpdateAsync 方法,但是 MustHaveHappened() 结果显示该方法没有 运行 对抗伪造的 collection.

有没有一种方法可以使用 FakeItEasy 来检测 FindOneAndUpdateAsync 方法 运行 当 collection 被 运行 反对时伪造的?

失败测试的错误消息

Assertion failed for the following call: Any call made to the fake object. where x => (x.Method.Name == "FindOneAndUpdateAsync") Expected to find it once or more but didn't find it among the calls: 1: MongoDB.Driver.IMongoCollection`1[ConsoleApp3.Fruit].WithWriteConcern(writeConcern: { w : "majority" })

使用 FakeItEasy 进行单元测试

    [Fact]
    public async Task TestFruitUpdate()
    {
        IDBContext fakeDbContext = A.Fake<DBContext>();
        var fakeMongoCollection = A.Fake<IMongoCollection<Fruit>>();
        var fruitEntity = new Fruit()
        {
            Id = new MongoDB.Bson.ObjectId(),
            Name = "Apple",
            Price = 2.0,
            Quantity = 3,
        };

        A.CallTo(() => fakeDbContext.GetCollection<Fruit>()).Returns(fakeMongoCollection);
        A.CallTo(fakeDbContext).WithReturnType<IMongoCollection<Fruit>>().Returns(fakeMongoCollection);

        var repository = new FruitRepository(fakeDbContext);

        await repository.UpdateFruitQuantityAsync(fruitEntity);

        A.CallTo(fakeMongoCollection).Where(x => x.Method.Name == "FindOneAndUpdateAsync").MustHaveHappened();
    }

DBContext 的接口

public interface IDBContext
{
    IMongoClient Client { get; }

    IMongoDatabase Database { get; }

    IMongoCollection<TDocument> GetCollection<TDocument>()
        where TDocument : Fruit;
}

水果实体

public class Fruit
{
    public ObjectId Id { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
    public int Quantity { get; set; }
}

水果库Class

class FruitRepository
{
    private readonly IDBContext _dbContext;

    public FruitRepository(IDBContext dBContext) =>
        _dbContext = dBContext;

    public virtual Task UpdateFruitQuantityAsync(Fruit fruitEntity) =>
        _dbContext.GetCollection<Fruit>()
            .WithWriteConcern(WriteConcern.WMajority)
            .FindOneAndUpdateAsync(
                Builders<Fruit>.Filter.Eq(j => j.Id, fruitEntity.Id),
                Builders<Fruit>.Update.Set(j => j.Quantity, fruitEntity.Quantity)
             );
}

问题是 WithWriteConcern 的结果不是 fakeMongoCollection。这就是 FakeItEasy 没有看到 FindOneAndUpdateAsync 调用的原因,即使您在调试时看到了对 something 的调用。有时在这些令人困惑的情况下,检查测试中对象的身份 (ReferenceEquals) 是值得的。

使用了新的 Fake,因为您配置了 fakeDbContext 两次。您的第二个电话应该在要求 IMongoCollection<Fruit>:

时将 fakeMongoCollection 配置为 return 本身
A.CallTo(fakeDbContext).WithReturnType<IMongoCollection<Fruit>>()
    .Returns(fakeMongoCollection);

A.CallTo(fakeMongoCollection).WithReturnType<IMongoCollection<Fruit>>()
     .Returns(fakeMongoCollection);