【问题标题】:Mocked object returning null object instead of List模拟对象返回空对象而不是列表
【发布时间】:2014-10-15 19:50:43
【问题描述】:

使用 Moq,我有一个模拟对象,它应该从函数调用返回 List<>。返回的对象是null,我不知道为什么。

在这里我创建了模拟对象并设置函数返回一个List

var mockParser = new Mock<ISalesParser>() { CallBase = false };
        mockParser.Setup(m => m.Parse(It.IsAny<string>())).Returns(new List<ImportedData>{ new ImportedData{ ReportingPeriod = DateTime.Now } });

它是被测函数,我调用Parse() 并捕获返回的对象。当我尝试获取列表的Count 时,它会引发System.ArgumentNullExcpetion : Value cannot be null 异常。

我对 mocking 和 Moq 还很陌生,有什么我遗漏的吗?

测试方法:

[Test]
    public void Test_ImportNormalExecution()
    {
        var importedData = new Mock<List<ImportedData>>(MockBehavior.Strict) { CallBase = false };
        importedData.SetupAllProperties();
        importedData.As<IEnumerable<ImportedData>>().Setup(m => m.GetEnumerator()).Returns(importedList.GetEnumerator());

        var mockParser = new Mock<ISalesParser>() { CallBase = false };
        mockParser.Setup(m => m.Parse(It.IsAny<string>())).Returns(new List<ImportedData>{ new ImportedData{ ReportingPeriod = DateTime.Now } });
        mockParser.Setup(m => m.Parse(It.IsAny<string>())).Callback(() => parseFuncCall++);

        var mockContext = new Mock<ApplicationDbContext>() { CallBase = true };
        mockContext.As<IUnitOfWork>().CallBase = false;
        mockContext.Setup(m => m.ImportedData.Add(It.IsAny<ImportedData>())).Callback(() => addImportDataCall++);

        unitOfWork = new UnitOfWork(mockContext.Object);
        dataRepository = new ImportedDataRepository(mockContext.Object);
        parser = mockParser.Object;

        service = new SalesService(parser, dataRepository, unitOfWork);
        string status = "Parsed input file.  Processed imported data into sales history.";
        SalesImportResults results = ((ISalesService)service).Import(AmazonHtmlSalesParserResources.AmazonHtmlDataValid);

        Assert.AreEqual(1, results.Count);
        Assert.That(parseFuncCall == 1);
        Assert.That(addImportDataCall == 1);
        Assert.That(String.Compare(status, results.Status) == 0);

    }

待测方法

public SalesImportResults ISalesService.Import(string data)
    {
        var salesImportResults = new SalesImportResults();

        try
        {
            IEnumerable<ImportedData> sales = _salesParser.Parse(data);

            salesImportResults.Count = sales.Count();
            salesImportResults.Date = sales.FirstOrDefault().ReportingPeriod;
            salesImportResults.Status = "Parsed input file.";

            foreach (ImportedData salesItem in sales)
            {
                _importedDatarepository.Add(salesItem);
            }
            _unitOfWork.SaveChanges();

            salesImportResults.Status += " Inserted data into import table.";

            _importedDatarepository.ProcessImportedData();

            salesImportResults.Status += " Processed imported data into sales history.";

            return salesImportResults;
        }
        catch (Exception ex)
        {
            throw new ApplicationException(salesImportResults.Status + " - but then something went wrong: " + ex.Message, ex);
        }

    }

异常被抛出salesImportResults.Count = sales.Count();

public interface ISalesParser
{
    IEnumerable<ImportedData> Parse(string data);
}

【问题讨论】:

  • 您能否包含其余的测试代码?
  • 从您提供的信息中并不明显。请提供异常的堆栈跟踪和被测方法,以及被调用方法可能在调用堆栈中调用的所有依赖代码。
  • 添加了测试函数和被测函数。
  • @IlyaIvanov 是的,ISalesParserpublic

标签: c# unit-testing moq


【解决方案1】:

当你打电话时

mockParser.Setup(m => m.Parse(It.IsAny<string>())).Callback(() => parseFuncCall++);

先前配置的返回值被重置,所以它再次为空。如果需要设置返回值和回调,可以将ReturnsCallback 方法链接在一起:

var mockParser = new Mock<ISalesParser>() { CallBase = false };
mockParser.Setup(m => m.Parse(It.IsAny<string>()))
    .Returns(new List<ImportedData>{ new ImportedData{ ReportingPeriod = DateTime.Now } })
    .Callback(() => parseFuncCall++);

【讨论】:

  • @DFord 在旁注中,“正确”的方法来做你试图用回调做的事情是摆脱你的回调并用mockParser.Verify(m =&gt; m.Parse(It.IsAny&lt;string&gt;()), Times.Once); 替换你的Assert.That(parseFuncCall == 1);。此外,如果您只想检查您的函数是否被调用“一次或多次”,只需执行 .Verifiable() 而不是回调,那么最后只需调用 mockParser.Verify(); 它将检查所有标记为 .Verifiable() 的方法是否至少被调用一次。
  • @ScottChamberlain 感谢您的提示。我需要更多地探索起订量并学习“正确”的使用方式。
猜你喜欢
  • 2018-12-18
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
  • 1970-01-01
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多