如何使用 MSpec 为接口的所有实现编写通用测试?
我有一个接口 IAudioProcessor
,具有单个方法 IEnumerable
。虽然这不是接口本身的要求,但我想确保我的所有实现都遵循一些通用规则,例如:
- 使用延迟执行
- 不要更改输入样本
为这些创建测试并不难,但是我必须为每个实现复制并粘贴这些测试。我想避免这种情况。
我想做这样的事情(注意属性 GenericTest
和类型参数):
[GenericTest(typeof(AudioProcessorImpl1Factory))]
[GenericTest(typeof(AudioProcessorImpl2Factory))]
[GenericTest(typeof(AudioProcessorImpl3Factory))]
public class when_processed_audio_is_returned<TSutFactory>
where TSutFactory : ISutFactory<IAudioProcessor>, new()
{
static IAudioProcessor Sut = new TSutFactory().CreateSut();
protected static Context _ = new Context();
Establish context = () => _.Original = Substitute.For<IEnumerable<ISample>>();
Because of = () => Sut.Process(_.Original);
It should_not_have_enumerated_the_original_samples = () =>
{
_.Original.DidNotReceive().GetEnumerator();
((IEnumerable)_.Original).DidNotReceive().GetEnumerator();
};
}
这样的事情可能吗?
I have an interface IAudioProcessor
with a single method IEnumerable<Sample> Process(IEnumerable<Sample> samples)
. While it is not a requirement of the interface itself, I want to make sure that all my implementations follow some common rules, like for example:
- Use deferred execution
- Don't change the input samples
It is not hard to create tests for these, but I would have to copy and paste these tests for each implementation. I would like to avoid that.
I would like to do something like this (note the attribute GenericTest
and the type parameter):
[GenericTest(typeof(AudioProcessorImpl1Factory))]
[GenericTest(typeof(AudioProcessorImpl2Factory))]
[GenericTest(typeof(AudioProcessorImpl3Factory))]
public class when_processed_audio_is_returned<TSutFactory>
where TSutFactory : ISutFactory<IAudioProcessor>, new()
{
static IAudioProcessor Sut = new TSutFactory().CreateSut();
protected static Context _ = new Context();
Establish context = () => _.Original = Substitute.For<IEnumerable<ISample>>();
Because of = () => Sut.Process(_.Original);
It should_not_have_enumerated_the_original_samples = () =>
{
_.Original.DidNotReceive().GetEnumerator();
((IEnumerable)_.Original).DidNotReceive().GetEnumerator();
};
}
Is something like this possible?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我很确定您正在寻找行为(另请参阅此行为文章的行测试)。您将在共享 SUT 和支持字段(根据需要)的特殊类中定义每个实现应满足的行为(
It
字段)。您的每个实现都需要声明它们的行为类似于这个特殊的类。您已经有一个相当复杂的基类,具有共享的设置和行为,所以我将使用它(我更喜欢更简单、更明确的设置)。
您的基类定义了通用设置(捕获上下文枚举)、行为(通过类型参数使用特定的 impl 进行处理),甚至声明行为字段(同样,由于通用类型参数,这将为每个具体对象运行) )。
此外,您还将获得每个实现类的每个
It
字段的输出。这样您的背景/规格报告就完整了。I'm pretty sure you're looking for Behaviors (also see this row test with behaviors article). You will define the behaviors that every implementation should satisfy (the
It
fields) in a special class that share the SUT and supporting fields (as necessary).Each of your implementations need to declare that they behave like this special class. You already had a pretty complicated base class with shared setup and behavior, so I'll use it (I prefer a simpler, more explicit setup).
Your base class defines the common setup (capturing the context enumeration), behavior (processing with the specific impl via the type parameter), and even declaring the behaviors field (again, thanks to the generic type parameter, this will be run for every concrete).
Additionally, you will get output for each of the
It
fields for each of the implementing classes. So your context/spec reports will be complete.我为您进行了 Binged MSpec 参数化测试 :) http://groups. google.com/group/machine_users/browse_thread/thread/8419cde3f07ffcf2?pli=1
不会显示为单独的绿色/红色测试,我认为没有什么可以阻止您从单个规范中枚举一系列工厂并断言每个实现的行为。这意味着即使一个实现失败,你的测试也会失败,但如果你想要参数化,你可以尝试像 NUnit 这样更宽松的测试套件。
编辑1:我不确定MSpec是否支持发现继承字段来确定规范,但如果是这样,下面的代码至少应该最大限度地减少“重复”代码的数量,而无法使用属性:
I Binged MSpec paramaterised tests for you :) http://groups.google.com/group/machine_users/browse_thread/thread/8419cde3f07ffcf2?pli=1
Whilst it won't show up as a separate green/red test, I don't think there's anything preventing you from enumerating a sequence of factories from within your single spec and assert the behaviour for each implementation. It'll mean your test fails even if one implementation fails, but if you want parameterisation you might try a looser testing suite like NUnit.
Edit 1: I'm not sure if MSpec supports discovery of inherited fields to determine a spec, but if so the below should at least minimise the amount of "repeated" code without being able to use an attribute: