FakeItEasy不返回期望值

时间:2019-11-04 21:39:16

标签: c# unit-testing nunit fakeiteasy

我正在尝试测试一种将字典作为参数的方法,通过删除一些不必要的条目对其进行过滤并返回结果字典。我已经单独编写了用于过滤类的测试,这些测试可以正常工作,因此该测试仅与调用过滤器并返回字典有关。

由于某种原因,即使我特别告诉它使用FakeItEasy返回什么,过滤器也会返回空字典。 _callToChartOfAccountsFilterer断言失败,并显示以下消息:

    Assertion failed for the following call:
    TinyBooks.Services.Json.ChartOfAccounts.IChartOfAccountsFilterer.FilterAccounts(dictionary: Ignored, filteringParameters: Ignored)
  Expected to find it once exactly but didn't find it among the calls:
    1: TinyBooks.Services.Json.ChartOfAccounts.IChartOfAccountsFilterer.FilterAccounts(dictionary: [[Group1, System.Collections.Generic.List`1[TinyBooks.DomainModel.Dtos.AccountForParserDto]]], filteringParameters: TinyBooks.Services.Json.ChartOfAccounts.ChartOfAccountsFilteringParameters)

ChartOfAccountsParser

public class ChartOfAccountsParser : IChartOfAccountsParser
{
    private readonly IJsonDeserializer _jsonDeserializer;
    private readonly IChartOfAccountsFilterer _chartOfAccountsFilterer;

    public ChartOfAccountsParser(IJsonDeserializer jsonDeserializer, IChartOfAccountsFilterer chartOfAccountsFilterer)
    {
        _jsonDeserializer = jsonDeserializer;
        _chartOfAccountsFilterer = chartOfAccountsFilterer;
    }

    public Dictionary<string, List<AccountForParserDto>> GetChartOfAccountsDictionaryBasedOnJsonFile(
        ChartOfAccountsParsingParameters parsingParameters)
    {
        var filePath = GetPathOfJsonFile(parsingParameters.FileName);
        var dictionary = ParseJsonToDictionary(filePath);
        var dic = _chartOfAccountsFilterer.FilterAccounts(dictionary, (ChartOfAccountsFilteringParameters)parsingParameters);
        return dic;
    }

    private string GetPathOfJsonFile(string fileName) => Path.Combine(GetFolderOfExecutingAssembly(), "ChartOfAccounts\\Json", fileName);

    private string GetFolderOfExecutingAssembly()
        => new Uri(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException()).LocalPath;

    private Dictionary<string, List<AccountForParserDto>> ParseJsonToDictionary(string filePath) 
        => _jsonDeserializer.Load<Dictionary<string, List<AccountForParserDto>>>(filePath);
}

ChartOfAccountsParserTests

 [TestFixture]
public class ChartOfAccountsParserTests
{
    private IJsonDeserializer _jsonDeserializer;
    private IChartOfAccountsFilterer _chartOfAccountsFilterer;
    private AccountForParserDto _dto;
    private ChartOfAccountsParsingParameters _parameters;
    private string _key;
    private List<AccountForParserDto> _group;
    private Dictionary<string, List<AccountForParserDto>> _dictionary;
    private IReturnValueArgumentValidationConfiguration<Dictionary<string, List<AccountForParserDto>>> _callToJsonDeserializer;
    private IReturnValueArgumentValidationConfiguration<Dictionary<string, List<AccountForParserDto>>> _callToChartOfAccountsFilterer;

    [SetUp]
    public void Setup()
    {
        _jsonDeserializer = A.Fake<IJsonDeserializer>();
        _chartOfAccountsFilterer = A.Fake<IChartOfAccountsFilterer>();

        _dto = new AccountForParserDto { Name = "Account1" };
        _parameters = new ChartOfAccountsParsingParameters { FileName = "a.json" };
        _key = "Group1";
        _group = new List<AccountForParserDto> { _dto };
        _dictionary = new Dictionary<string, List<AccountForParserDto>> { [_key] = _group} ;

        _callToJsonDeserializer = A.CallTo(() => _jsonDeserializer.Load<Dictionary<string, List<AccountForParserDto>>>(A<string>._));
        _callToChartOfAccountsFilterer = A.CallTo(() => _chartOfAccountsFilterer.FilterAccounts(
            A<Dictionary<string, List<AccountForParserDto>>>._,
            A<ChartOfAccountsParsingParameters>._));

        _callToJsonDeserializer.Returns(_dictionary);
        _callToChartOfAccountsFilterer.Returns(_dictionary);
    }

    [Test]
    public void GetChartOfAccountsDictionaryBasedOnJsonFile_GivenDictionaryIgnoringParameters_ReturnsSameDictionary()
    {
        var parser = new ChartOfAccountsParser(_jsonDeserializer, _chartOfAccountsFilterer);

        var result = parser.GetChartOfAccountsDictionaryBasedOnJsonFile(_parameters);

        Assert.That(result.ContainsKey(_key));
        Assert.That(result.ContainsValue(_group));
        _callToJsonDeserializer.MustHaveHappenedOnceExactly();
        _callToChartOfAccountsFilterer.MustHaveHappenedOnceExactly();
    }
}

2 个答案:

答案 0 :(得分:1)

根据您的示例,使用以下支持成员作为概念证明。

public class Parser {
    private readonly IFilter filter;
    private readonly IProvider provider;

    public Parser(IFilter filter, IProvider provider) {
        this.filter = filter;
        this.provider = provider;
    }

    public Dictionary<string, List<Dto>> GetData() {
        Dictionary<string, List<Dto>> input = provider.Load();
        var dictionary = filter.Filter(input);
        return dictionary;
    }
}

public interface IProvider {
    Dictionary<string, List<Dto>> Load();
}

public interface IFilter {
    Dictionary<string, List<Dto>> Filter(Dictionary<string, List<Dto>> input);
}

public class Dto {
    public string Name { get; set; }
}

以下测试的行为符合预期

[TestClass]
public class DictionaryTests {
    [TestMethod]
    public void Sohuld_Return_Expected_Data() {
        //Arrange
        var key = "Group1";
        var dto = new Dto { Name = "Account1" };
        var group = new List<Dto> { dto };
        var dictionary = new Dictionary<string, List<Dto>> {
            { key, group }
        };

        var provider = A.Fake<IProvider>();
        A.CallTo(() => provider.Load()).Returns(dictionary);

        var filter = A.Fake<IFilter>();
        A.CallTo(() => filter.Filter(A<Dictionary<string, List<Dto>>>._))
            .Returns(dictionary);

        var subjectUnderTest = new Parser(filter, provider);

        //Act
        var actual = subjectUnderTest.GetData();

        //Assert - using FluentAssertions
        actual.ContainsKey(key).Should().BeTrue();
        actual.ContainsValue(group).Should().BeTrue();
    }
}

答案 1 :(得分:1)

我终于弄清楚了。

问题出在此调用中被忽略参数的类型上

_callToChartOfAccountsFilterer = A.CallTo(() => _chartOfAccountsFilterer.FilterAccounts(
            A<Dictionary<string, List<AccountForParserDto>>>._,
            A<ChartOfAccountsParsingParameters>._));

不幸的是,我没有显示的是方法签名:

public interface IChartOfAccountsFilterer
{
    Dictionary<string, List<AccountForParserDto>> FilterAccounts(
        Dictionary<string, List<AccountForParserDto>> dictionary,
        IChartOfAccountsFilteringParameters filteringParameters);
}

当我将A<ChartOfAccountsParsingParameters>._更改为A<IChartOfAccountsFilteringParameters>._时,测试通过了。