我试图验证特定的CancellationTokenSource是否用作方法调用中的实际参数。
public void DataVerification(Object sender, EventArgs e)
{
_entity.PopulateEntityDataVerificationStage(_view.DataTypeInputs, _view.ColumnNameInputs, _view.InitialRow, _view.FinalRow, _view.CurrencyPair, _view.CsvFilePath, _view.ErrorLogFilePath);
//...
CancellationTokenSource tempCsvFileVerificationCancellation = new CancellationTokenSource();
_source.Source = tempCsvFileVerificationCancellation;
//Want to verify that TempCsvFileVerificationCancellation.Token is passed into the following method.
_verify.SetupCsvFileVerification(_entity, tempCsvFileVerificationCancellation.Token);
//...
}
以下是我的测试:
[Test]
public void DataVerification_SetupCsvFileVerification_CorrectInputs()
{
Mock<IMainForm> view = new Mock<IMainForm>();
Mock<IUserInputEntity> entity = new Mock<IUserInputEntity>();
Mock<ICsvFileVerification> verify = new Mock<ICsvFileVerification>();
verify.Setup(x => x.SetupCsvFileVerification(It.IsAny<UserInputEntity>(), It.IsAny<CancellationToken>()));
CancellationTokenSource cts = new CancellationTokenSource();
Mock<ICancellationTokenSource> source = new Mock<ICancellationTokenSource>();
source.SetupSet(x => x.Source = It.IsAny<CancellationTokenSource>()).Callback<CancellationTokenSource>(value => cts = value);
source.SetupGet(x => x.Source).Returns(cts);
source.SetupGet(x => x.Token).Returns(cts.Token);
MainPresenter presenter = new MainPresenter(view.Object, entity.Object, verify.Object, source.Object);
presenter.DataVerification(new object(), new EventArgs());
verify.Verify(x => x.SetupCsvFileVerification(entity.Object, source.Object.Token));
}
错误消息如下:
模拟上的预期调用至少一次,但从未执行过:x =&gt; x.SetupCsvFileVerification(.entity.Object,(Object).source.Object.Token) 没有配置设置。
源代表的类如下:
public interface ICancellationTokenSource
{
void Cancel();
CancellationTokenSource Source { get; set; }
CancellationToken Token { get; }
}
public class CancellationTokenSourceWrapper : ICancellationTokenSource
{
private CancellationTokenSource _source;
public CancellationTokenSourceWrapper(CancellationTokenSource source)
{
_source = source;
}
public CancellationTokenSource Source
{
get
{
return _source;
}
set
{
_source = value;
}
}
public CancellationToken Token
{
get
{
return Source.Token;
}
}
public void Cancel()
{
_source.Cancel();
}
}
当我逐步完成单元测试时,cts会被赋予TempCsvFileVerificationCancellation的值。 source中的Token属性返回Source.Token。我不知道自己做错了什么。
任何指示/协助都将不胜感激。
由于
修改
答案 0 :(得分:2)
乍一看,它看起来应该可以正常工作但是你可能不会尝试:
将验证的匹配条件更改为 It.IsAny(),It.IsAny()以查看是否完全调用它。 - 如果没有,请通过代码调试并查看发生的情况 - 如果它匹配,那么这是匹配的问题
尝试使用 entity.Object,It.IsAny()来查看UserInputEntity是否错误。
如果UserInputEntity正常,则在源安装程序上放置回调。它不需要执行任何操作,但可以在调用SetupCsvFileVerification时检查正在使用的值。
更新
我想我找到了它,它与我下面的一点有关。您将 cts 初始化为值。它需要有一个初始值,因为设置
source.SetupGet(x => x.Source).Returns(cts);
source.SetupGet(x => x.Token).Returns(cts.Token);
没有它就失败,因为它会立即评估cts.Token。这意味着这将从测试中定义的CancellationTokenSource返回令牌,不是生产代码中定义的令牌(并使用回调存储)。
要确保使用新的cts值,您应该将设置更改为
source.SetupGet(x => x.Source).Returns(() => cts);
source.SetupGet(x => x.Token).Returns(() => cts.Token);
将推迟评估直到使用,即从集合的回调执行之后。
已添加详细信息
问题是评估的时间
在测试设置中说你创建了一个带有令牌A的cts X.
然后设置Source以返回cts和令牌以返回cts.Token
这些被评估为现在,获取被告知返回X和A.
运行时,cts被一组使用回调覆盖(称为Y,令牌为B),它是验证使用的B值,因此失败。
通过更改设置以使用lambdas,我们告诉他们使用'当你调用'时cts指向的值是什么,所以序列现在是
设置get - 不评估CTS或令牌值
呼叫验证
- 使用回调设置cts
- get source =&gt;评估,使用新设定值(Y)
- get token =&gt;评估,使用新设定值(B)
验证=&gt;与B比较,通过
其他想法
CancellationTokenSource是否仅存在以支持测试?
如果是这样,另一种方法是尝试用 ICancellationTokenProvider 替换它,这将替换生产代码中的 new CancellationTokenSource(); 调用。这将允许您更轻松地将特定的CancellationToken注入代码,从而验证SetupCsvFileVerification()。
轻微的狡辩 - 随意忽略
此外,除非您使用严格的行为设置
verify.Setup(x => x.SetupCsvFileVerification(It.IsAny<UserInputEntity>(),
It.IsAny<CancellationToken>()));
是多余的。它不会返回任何内容,因此它不适用于存根,并且您将在以后明确验证该调用。
同样,不需要将'cts'初始化为值,将其设置为null就足够了,因为设置源的回调应该填充它。