Moq C# MongoDB FindAsync return 值

Moq C# MongoDB FindAsync return value

最近我们为 Mongo.

实现了通用版本的存储库

存储库

public async Task<IList<T>> FindAsync<T>(FilterDefinition<T> t) where T : IMongoModel
{
    var collection = _connection.GetCollection<T>();
    var result = await collection.FindAsync<T>(t);
    return await result.ToListAsync();
}

public async Task<IList<T>> FindAsync<T>(Expression<Func<T, bool>> filter) where T : IMongoModel
{
    var collection = _connection.GetCollection<T>();
    var result = await collection.FindAsync(filter);
    return await result.ToListAsync();
}

正在调用的代码

private async Task<MongoDb.Advertisement.Service.Models.AdvertisementFiles.Advertisement> DealerZipCodeAndLocation(MongoDb.Advertisement.Service.Models.AdvertisementFiles.Advertisement advertisement, string searchPhone)
{
    var matchingDealers = await _mongoRepository.FindAsync(Builders<Dealer>.Filter.ElemMatch(y => y.Phones, z => z.PhoneNumber == searchPhone));
    if (!matchingDealers.Any())
    {
        return advertisement;
    }
    if (matchingDealers.Count > 1)
    {
        _logger.Warning("More than one dealer found with {PhoneNumber}", searchPhone);
    }
    var matchingDealer = matchingDealers.FirstOrDefault();
    if (matchingDealer.Geocode == null)
    {
        var geoCode = await _geoLocationCache.GetGeocodByZipCode(matchingDealer.Address.ZipCode);

        if (geoCode.status != "OK")
        {
            return advertisement;
        }
        advertisement.Geocode = geoCode;
        advertisement.ZipCode = matchingDealer.Address.ZipCode;
        await UpdateGeocode<Dealer>(matchingDealer.Id, geoCode);
    }

    return advertisement;
}

也试过以下签名

var matchingDealers = await _mongoRepository.FindAsync<Dealer>(x => x.Phones.Any(y => y.PhoneNumber == searchPhone));
var matchingDealers = await _mongoRepository.FindAsync(filter);

模拟 FindAsync 调用时,我遇到了 return 的困难。问题要么是签名不匹配,要么更可能是异步。

最小起订量设置 我已经尝试了两个版本(也用 It.IsAny<string>() 代替 phone 号码)

_testFixture.MongoRepository.Setup(x => x.FindAsync(Builders<Dealer>.Filter.ElemMatch(y => y.Phones, z => z.PhoneNumber == _testFixture.GetAdvertisementWithNoZipCode().OriginalPhoneNumber))).Returns(Task.FromResult(_testFixture.GetDealerWithZipCode()));
_testFixture.MongoRepository.Setup(x => x.FindAsync(Builders<Dealer>.Filter.ElemMatch(y => y.Phones, z => z.PhoneNumber == _testFixture.GetAdvertisementWithNoZipCode().OriginalPhoneNumber))).ReturnsAsync(_testFixture.GetDealerWithZipCode());

Return 对象尝试

public IList<Dealer> GetDealerWithZipCode()
{
    return new List<Dealer>
    {
        new Dealer
        {
            Active = true,
            DealerName = "City Chevrolet",
            Phones = new List<Phone>
            {
                new Phone
                {
                    PhoneNumber = "4033809999"
                }
            },
            MasterCode = "CHEV01",
            RevisionDate = DateTime.UtcNow
        }
    };
}

public async Task<IList<Dealer>> GetDealerWithZipCode()
{
    return await Task.Run(() => new List<Dealer>
    {
        new Dealer
        {
            Active = true,
            DealerName = "City Chevrolet",
            Phones = new List<Phone>
            {
                new Phone
                {
                    PhoneNumber = "4033809999"
                }
            },
            MasterCode = "CHEV01",
            RevisionDate = DateTime.UtcNow
        }
    });
}

异常

System.ArgumentNullException: Value cannot be null.
Parameter name: source
     at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source)
     at Domain.Advertisement.Service.BackgroundProcessors.ZipCodeAndLocationProcessor.<DealerZipCodeAndLocation>d__5.MoveNext() in C:\Repos\Vader\AdSvc\domain\domain.advertisement.service\BackgroundProcessors\ZipCodeAndLocationProcessor.cs:line 60
 --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
     at Domain.Advertisement.Service.BackgroundProcessors.ZipCodeAndLocationProcessor.<ProcessVehicleAdvertisementLocation>d__4.MoveNext() in C:\Repos\Vader\AdSvc\domain\domain.advertisement.service\BackgroundProcessors\ZipCodeAndLocationProcessor.cs:line 42
 --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
     at Domain.Advertisement.Service.Tests.Processors.ZipCodeAndLocation.ZipCodeAndLocationProcessorFacts.<ProcessVehicleAdvertisementLocation_AdLineHasEmptyZipCodePhoneMatchesDealer_GeocodeIsAddedToAdvertisement>d__3.MoveNext() in C:\Repos\Vader\AdSvc\tests\domain.advertisement.service.tests\Processors\ZipCodeAndLocation\ZipCodeAndLocationProcessorFacts.cs:line 47
 --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_1.<<InvokeTestMethodAsync>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at Xunit.Sdk.ExecutionTimer.<AggregateAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at Xunit.Sdk.ExceptionAggregator.<RunAsync>d__9.MoveNext()

当我调试时,我得到一个 ArgumentNullException,因为我没有得到我的 return 对象。我知道我的设置有问题,但我正在努力找出问题所在。

鉴于我假设的测试方法是 DealerZipCodeAndLocation 你应该能够如下设置存储库模拟

_testFixture.MongoRepository
    .Setup(_ => _.FindAsync(It.IsAny<FilterDefinition<Dealer>>()))
    .ReturnsAsync(_testFixture.GetDealerWithZipCode());

假设

这应该简化测试的预期
Task<IList<T>> FindAsync<T>(FilterDefinition<T> t) where T : IMongoModel

属于_testFixture.MongoRepository提供的repository接口,应该安全地将被测方法执行到

if (matchingDealer.Geocode == null) {
    //...

您还需要确保其他依赖项(如记录器和地理位置缓存)已正确模拟,以便按预期执行测试。