Неожиданная нулевая ссылка при тестировании с NUnit и Moq - PullRequest
1 голос
/ 18 марта 2019

Я получаю нулевую ссылку при выполнении теста, но не могу понять. Ниже мой тест

[Test]
[TestCase(...)]
public void Get_ShouldReturnTradesMock(string field, Operator op, int dayManip, SortDirection sortDir, string filterTerm, int pageIndex, int pageSize, int expectedRecordMinSize)
{
    using (var _imprintDbContext = new ImprintDbContext(_dbContextOptions))
    {
        var mockExecRepo = new Mock<IExecutionReportRepository>();
        mockExecRepo.Setup(mock => mock.GetFilteredTrades(It.IsAny<IEnumerable<Query>>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>())).Verifiable();//.Returns<Task<PagedResult<ExecutionReport>>>(x => null);

        var uow = new Mock<IUnitOfWork>();
        uow.SetupGet(x => x.ExecutionReports).Returns(mockExecRepo.Object);

        var controller = new TradesController(uow.Object);

        var query = new Query()
        {
            Field = field,
            Operator = op,
            Search = DateTime.Now.Add(TimeSpan.FromDays(dayManip)).Date.ToString("yyyy-MM-dd"),
            SortDirection = sortDir
        };

        TradesController.TradesBody tb = new TradesController.TradesBody()
        {
            queries = new[] { query },
            filterTerm = filterTerm
        };

        var results = controller.Get(tb, pageIndex, pageSize);

        uow.Verify(mock => mock.ExecutionReports.GetFilteredTrades(new[] { query }, pageIndex, pageSize, filterTerm), Times.Once());
    }
}

И определения некоторых объектов, над которыми я издеваюсь:

public interface IExecutionReportRepository : IRepository<ExecutionReport>
{
    ...
    Task<IPagedResult<ExecutionReport>> GetFilteredTrades(IEnumerable<Query> queries, int pageIndex, int pageSize, string filterTerm);

}

UnitOfWork:

public class UnitOfWork : IUnitOfWork
{
    private readonly DbContext _context;

    public UnitOfWork(DbContext context, IExecutionReportRepository executionReportRepository)
    {
        _context = context;
        ExecutionReports = executionReportRepository;
    }

    public IExecutionReportRepository ExecutionReports { get; }
}

TradesController:

public class TradesController : Controller
{
    public class TradesBody
    {
        public IEnumerable<Query> queries;
        public string filterTerm;
    }

    private readonly IUnitOfWork unitOfWork;

    public TradesController(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
    }

    /// <summary>
    /// Gets a list of trades for the current date
    /// </summary>
    [HttpPost]
    public async Task<IActionResult> Get([FromBody] TradesBody postBody, int pageIndex = 0, int pageSize = 100)
    {
            string filterTerm = postBody.filterTerm ?? "";
            IEnumerable<Query> queries = postBody.queries;
            IPagedResult<Domain.Entities.Core.ExecutionReport> queryResult;
            queryResult = await unitOfWork.ExecutionReports.GetFilteredTrades(queries, pageIndex, pageSize, filterTerm); //Null reference error here
            return Ok(queryResult);
    }
}

При просмотре кода я не вижу нулевых объектов и, следовательно, не могу увидеть / понять, где на самом деле находится нулевая ссылка, однако я заметил, что не вижу определения метода во время отладки для 'GetFilteredTrades. Судя по this , мой смоделированный метод не подключается к выполняемому методу, однако у меня есть только один GetFilteredTrades.

Как устранить ошибку нулевой ссылки, выдаваемую в TradesController, и успешно запустить мой тест?

1 Ответ

1 голос
/ 18 марта 2019

Вы не настраиваете GetFilteredTrades для возврата чего-либо, поэтому при попытке его ожидания происходит сбой.

mockExecRepo
    .Setup(mock => mock.GetFilteredTrades(It.IsAny<IEnumerable<Query>>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>()))
    .ReturnAsync(Mock.Of<IPagedResult<ExecutionReport>>()) //<--THIS
    .Verifiable();

Также тестируемый метод является асинхронным, поэтому тест также должен быть асинхронным.

[Test]
[TestCase(...)]
public async Task Get_ShouldReturnTradesMock(string field, Operator op, int dayManip, SortDirection sortDir, string filterTerm, int pageIndex, int pageSize, int expectedRecordMinSize)
{

и ожидание вызова тестируемого метода

var results = await controller.Get(tb, pageIndex, pageSize);

Наконец, вы проверяете неправильный макет на основе настройки.Поскольку для настройки mockExecRepo установлено значение Verifiable(), вы можете просто вызвать Verify() на макете.

//...

//Act
var results = await controller.Get(tb, pageIndex, pageSize);

//Assert
mockExecRepo.Verify();

, чтобы убедиться, что он был вызван так, как ожидалось.

...