Moq C#MongoDB FindAsync返回值

时间:2017-05-09 21:34:04

标签: c# mongodb moq xunit.net

最近我们为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调用时,我对返回有困难。问题是签名不匹配,或者更可能是异步。

Moq设置 我已尝试过两个版本(同时使用It.IsAny<string>()代替电话号码)

_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());

尝试返回对象

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,因为我没有得到我的返回对象。我知道我的设置存在问题,但我正在努力弄清楚在哪里。

1 个答案:

答案 0 :(得分:0)

鉴于我所假设的测试方法是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提供的存储库接口,应该可以安全地将测试中的方法运用到行

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

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