FakeItEasy 没有 return 期望值
FakeItEasy does not return expected value
我正在尝试测试一种方法,该方法将字典作为参数,通过删除一些不必要的条目和 return 生成的字典来过滤它。我已经单独编写了过滤 class 正常工作的测试,所以这个测试只涉及被调用的过滤器和 returning 字典。
出于某种原因,过滤器 return 的字典是空的,即使我用 FakeItEasy 明确告诉它要 return 什么。
_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();
}
}
使用以下支持成员作为基于您的示例的概念证明。
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();
}
}
好吧,我终于想通了。
问题在于此调用中被忽略的参数的类型:
_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>._
时,测试通过了。
我正在尝试测试一种方法,该方法将字典作为参数,通过删除一些不必要的条目和 return 生成的字典来过滤它。我已经单独编写了过滤 class 正常工作的测试,所以这个测试只涉及被调用的过滤器和 returning 字典。
出于某种原因,过滤器 return 的字典是空的,即使我用 FakeItEasy 明确告诉它要 return 什么。
_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();
}
}
使用以下支持成员作为基于您的示例的概念证明。
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();
}
}
好吧,我终于想通了。
问题在于此调用中被忽略的参数的类型:
_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>._
时,测试通过了。