gpt4 book ai didi

refactoring - Autofixture 生成自定义列表

转载 作者:行者123 更新时间:2023-12-03 11:53:09 24 4
gpt4 key购买 nike

这是我的对象:

public class Symbol
{
private readonly string _identifier;
private readonly IList<Quote> _historicalQuotes;

public Symbol(string identifier, IEnumerable<Quote> historicalQuotes = null)
{
_identifier = identifier;
_historicalQuotes = historicalQuotes;
}
}

public class Quote
{
private readonly DateTime _tradingDate;
private readonly decimal _open;
private readonly decimal _high;
private readonly decimal _low;
private readonly decimal _close;
private readonly decimal _closeAdjusted;
private readonly long _volume;

public Quote(
DateTime tradingDate,
decimal open,
decimal high,
decimal low,
decimal close,
decimal closeAdjusted,
long volume)
{
_tradingDate = tradingDate;
_open = open;
_high = high;
_low = low;
_close = close;
_closeAdjusted = closeAdjusted;
_volume = volume;
}
}

我需要一个用 Quote 列表填充的 Symbol 实例。

在我的测试中,我想验证我是否可以返回收盘价低于或高于特定值的所有报价。这是我的测试:
[Fact]
public void PriceUnder50()
{
var msftIdentifier = "MSFT";
var quotes = new List<Quote>
{
new Quote(DateTime.Parse("01-01-2009"), 0, 0, 0, 49, 0, 0),
new Quote(DateTime.Parse("01-02-2009"), 0, 0, 0, 51, 0, 0),
new Quote(DateTime.Parse("01-03-2009"), 0, 0, 0, 50, 0, 0),
new Quote(DateTime.Parse("01-04-2009"), 0, 0, 0, 10, 0, 0)
};

_symbol = new Symbol(msftIdentifier, quotes);


var indicator = new UnderPriceIndicator(50);
var actual = indicator.Apply(_symbol);

Assert.Equal(2, actual.Count);
Assert.True(actual.Any(a => a.Date == DateTime.Parse("01-01-2009")));
Assert.True(actual.Any(a => a.Date == DateTime.Parse("01-04-2009")));
Assert.True(actual.Any(a => a.Price == 49));
Assert.True(actual.Any(a => a.Price == 10));
}

好的。

现在,我想使用 Autofixture 来做这件事,我是一个真正的初学者。我已经在互联网上阅读了有关此工具的几乎所有内容(作者的博客、codeplex 常见问题解答、github 源代码)。我了解 autofixture 的基本功能,但现在我想在我的实际项目中使用 autofixture。这是我到目前为止所尝试的。
var msftIdentifier = "MSFT";

var quotes = new List<Quote>();
var random = new Random();
fixture.AddManyTo(
quotes,
() => fixture.Build<Quote>().With(a => a.Close, random.Next(1,49)).Create());
quotes.Add(fixture.Build<Quote>().With(a => a.Close, 49).Create());

_symbol = new Symbol(msftIdentifier, quotes);

// I would just assert than 49 is in the list
Assert.True(_symbol.HistoricalQuotes.Contains(new Quote... blabla 49));

理想情况下,我更愿意直接创建 Symbol 的夹具,但我不知道如何自定义我的报价列表。而且我不确定我的测试是否通用,因为在另一个测试中,我需要检查特定值是否高于而不是低于,因此我将复制“夹具代码”并手动添加引号 = 51.

所以我的问题是:

1 - 这是我应该如何使用 autofixture 的方式吗?

2 - 是否可以改进我在示例中使用 autofixture 的方式?

最佳答案

AutoFixture 最初是作为测试驱动开发 (TDD) 的工具而构建的,而 TDD 就是关于 反馈 .本着GOOS的精神,你应该聆听您的测试 .如果测试很难编写,您应该考虑您的 API 设计。 AutoFixture 倾向于放大这种反馈 ,这就是它告诉我的。

让比较更容易

首先,虽然与 AutoFixture 无关,但 Quote类只是乞求变成一个合适的值对象 ,所以我会覆盖 Equals为了更容易比较预期和实际实例:

public override bool Equals(object obj)
{
var other = obj as Quote;
if (other == null)
return base.Equals(obj);

return _tradingDate == other._tradingDate
&& _open == other._open
&& _high == other._high
&& _low == other._low
&& _close == other._close
&& _closeAdjusted == other._closeAdjusted
&& _volume == other._volume;
}

(确保也覆盖 GetHashCode。)

复制更新

上面的测试尝试似乎意味着我们缺乏一种方法来 改变单个字段,同时保持其余字段不变 .从函数式语言中得到启发,我们可以在 Quote 上介绍一种方法来做到这一点。类本身:
public Quote WithClose(decimal newClose)
{
return new Quote(
_tradingDate,
_open,
_high,
_low,
newClose,
_closeAdjusted,
_volume);
}

这种 API 在值对象上往往非常有用,以至于我总是将这些方法添加到我的值对象中。

让我们对 Symbol 做同样的事情:
public Symbol WithHistoricalQuotes(IEnumerable<Quote> newHistoricalQuotes)
{
return new Symbol(_identifier, newHistoricalQuotes);
}

这使得 更容易让 AutoFixture 处理您不关心的所有事情 同时只明确说明您关心的内容。

使用 AutoFixture 进行测试

原来的测试现在可以改写为:
[Fact]
public void PriceUnder50()
{
var fixture = new Fixture();
var quotes = new[]
{
fixture.Create<Quote>().WithClose(49),
fixture.Create<Quote>().WithClose(51),
fixture.Create<Quote>().WithClose(50),
fixture.Create<Quote>().WithClose(10),
};
var symbol = fixture.Create<Symbol>().WithHistoricalQuotes(quotes);
var indicator = fixture.Create<UnderPriceIndicator>().WithLimit(50);

var actual = indicator.Apply(symbol);

var expected = new[] { quotes[0], quotes[3] };
Assert.Equal(expected, actual);
}

此测试仅说明您关心的测试用例的那些部分,而 AutoFixture 负责处理对测试用例没有任何影响的所有其他值。这使得测试更加健壮,并且更具可读性。

关于refactoring - Autofixture 生成自定义列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17846164/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com