在阅读了另一个SO线程(Should parameters/returns of collections be IEnumerable<T> or T[]?)之后,我认为我所拥有的单元测试“问题”可能与线程所称的“迟到评估”有关。
我将三种不同但相关的IEnumerables从演示者类传递到我的UI。最好的消息是它有效,但我似乎无法找到一种方法来进行单元测试,最终证明正确的IEnumerable正在通过。
我有以下方法的外观:
public IEnumerable<DynamicDisplayDto> NonProjectDtos
{
get
{
var activities = LeaveTimeActivities.Cast<TimeSheetActivityBase>()
.Concat(AdministrativeActivities.Cast<TimeSheetActivityBase>());
return _assembler.ToActivityDtoCollection(activities, _timeSheet);
}
}
在演示者中,我加载了一个小部件:
private ITimeSheetMatrixWidget _nonProjectActivityMatrix;
public ITimeSheetMatrixWidget NonProjectActivityMatrix {
set {
..
// load the activities
_nonProjectActivityMatrix.Load(Facade.NonProjectDtos);
...
}
}
然后在模拟矩阵上进行测试(使用Rhino Mocks):
[Test]
public void SettingTheWidget_TriggersLoad_NonProjectActivities() {
var f = _getFacade();
...
// inject the mocked widget & trigger the Load
var widget = MockRepository.GenerateMock<ITimeSheetMatrixWidget>();
timeSheetPresenter.ActivityMatrix = widget;
widget.AssertWasCalled(x => x.Load(f.NonProjectDtos),
mo =>mo.IgnoreArguments()); <-- only way not to fail
//widget.AssertWasCalled(x => x.Load(f.NonProjectDtos)); <-- error
}
如果我查看调试器,我可以看到IEnumerable load arg正在评估Domain.TransferObjects.TimeSheetDtoAssembler + d _1,这也是Rhino消息中方法调用失败的部分。
这与后期评估有关吗?是否有一种相当优雅的方式来更严格地测试它?
我还想更好地理解中间评估,这看起来很像组装它的方法(在上面的外观代码中)。
答案 0 :(得分:3)
Facade对象在测试和被测试对象中是否相同 - 即,您是否也注入了Facade对象?如果对象不同,这将导致您看到的问题。如果它们是相同的,那么你可以在方法中实现枚举(使用ToList())。
答案 1 :(得分:2)
我只是想解决您的后期评估问题:
Cast
和Concat
(以及许多System.Linq.Enumerable
方法)都会返回符合IEnumerable<T>
的实例。枚举这些实例的实际结果是推迟的。为什么这些结果被推迟而不是急切地确定?
List<int> firstThreePrimes = Enumerable.Range(0, 1000000)
.Where(i => isPrime(i))
.Take(3)
.ToList();
ToList
枚举IEnumerable<int>
的{{1}}结果。 Take(3)
未生成任何数字,Range
过滤或Where
限制,直到Take
枚举此结果。
如果急切地确定了Range的结果,我们将生成1000000个整数。
如果急切地确定ToList
的结果,那么运行时必须将所有这1000000个整数发送到我们的Where
方法。
相反,调用序列看起来像这样。
isPrime
使用调试器很容易确认。只需单步执行即可查看Range
return from Range
Where
return from Where
Take
return from Take
ToList
GetEnumerator(Take)
GetEnumerator(Where)
GetEnumerator(Range)
return 0
isPrime(0) is false
return 1
isPrime(1) is false
return 2
isPrime(2) is true
2 is the first result
List.Add(2)
return 3
isPrime(3) is true
3 is the second result
List.Add(3)
return 4
isPrime(4) is false
return 5
isPrime(5) is true
5 is the third result
List.Add(5)
break;
。
从检查代码开始,看起来isPrime
可能会枚举结果,您可能没有遇到延迟执行。
答案 2 :(得分:2)
Rhino mocks工作得很好,虽然它并不总是能够知道为什么你使用了错误的语法或约束: - )
检查IEnumerable参数是否相等的方法只是使用以下内联约束:
Arg<T>.List.Equal(yourList)
以下是一个完整的例子:
[Test]
public void NonProjectMatrix_Injection_IsLoaded()
{
_nonProjectMatrix = MockRepository.GenerateMock<ITimeSheetMatrixWidget>();
var dtos = _facade.NonProjectDtos;
nonProjectMatrix.Expect(x => x.Load(Arg<IEnumerable<DynamicDisplayDto>>.List.Equal(dtos))).Return(dtos.Count());
new MatrixEntryService(_facade, _projectMatrix, _nonProjectMatrix, _totalMatrix);
_nonProjectMatrix.VerifyAllExpectations();
}
所以问题实际上与延迟执行无关。犀牛只是吐出所有它知道的一个电话没有像我告诉它期望的那样,这就是IEnumerable看待期望失败的时间。
干杯..