我的理解是每个Establish
只应执行一次,但下面的代码显示它执行多次。我们正在嵌套类以提供一些分组,同时在一个文件中保持Subject的单元测试。这似乎是一个错误。
我们正在使用machine.specifications.runner.resharper Reshaper扩展和MSpec 0.9.1。
[Subject(typeof(string))]
internal class EstablishRunTwice {
Establish sharedContext = () => Console.WriteLine("Shared context");
internal class ScenarioA : EstablishRunTwice {
Establish scenarioAContext = () => Console.WriteLine("ScenarioA context");
internal class ScenarioAVariation1 : ScenarioA {
Because of = () => Console.WriteLine("ScenarioAVariation1 Because");
It it1 = () => Console.WriteLine("ScenarioAVariation1 It1");
It it2 = () => Console.WriteLine("ScenarioAVariation1 It2");
}
internal class ScenarioAVariation2 : ScenarioA {
Because of = () => Console.WriteLine("ScenarioAVariation2 Because");
It it1 = () => Console.WriteLine("ScenarioAVariation2 It1");
It it2 = () => Console.WriteLine("ScenarioAVariation2 It2");
}
}
internal class ScenarioB : EstablishRunTwice {
Establish context = () => Console.WriteLine("ScenarioB context");
Because of = () => Console.WriteLine("ScenarioB Because");
It it1 = () => Console.WriteLine("ScenarioB It1");
It it2 = () => Console.WriteLine("ScenarioB It2");
}
}
结果是ScenarioAVariation1:
Shared context
Shared context
ScenarioA context
Shared context
Shared context
ScenarioA context
ScenarioAVariation1 Because
ScenarioAVariation1 It1
ScenarioAVariation1 It2
当我们使用NUnit进行自己的自定义上下文规范框架时,我们通过确保所有子类都是抽象的(在这种情况下,EstablishRunTwice和ScenarioA将是抽象的)来解决运行NUnit的问题,但是MSpec会抛出错误尝试这样做。
答案 0 :(得分:0)
这是构建事物的一种非常令人困惑的方式 - 聪明,但也许有点太聪明。我发现很难阅读和理解意图。事实上,我甚至无法想象编译器会对继承结构做什么,因此我无法理解意图。我想也许你过度思考了这一点。
让我看一下,ScenarioA
不仅嵌套在EstablishRunTwice
中,而且还从中继承。这是否意味着它一直继承自身的嵌套副本到无穷大?然后,ScenarioB
继承了所有这些!我的脑袋爆炸了。我对你得到令人困惑的结果并不感到惊讶。嵌套真正给你的是什么?它是否使代码更易读或更易于维护?我不相信它确实如此。
使用KISS原则。正常的做法是将每个上下文放在自己的类中,不嵌套;只需使用文件对相关测试进行分组,您也可以使用Concern
属性中的[Subject]
参数作为另一种分组方式。如果有意义的话,你可以从其他上下文继承,但是在使用MSpec几年之后,我慢慢得出结论,过多的继承可能会损害可读性并使测试代码更加粘稠,所以使用继承明智。
更新:反思了我想要实现的想法,我怀疑你正试图重新发明行为。这可能是MSpec的一个记录和理解不佳的特性,它允许您定义一组可以在以后在多个测试上下文中应用的常见行为。这听起来像你想要实现的那样吗?这是一个行为的例子:
[Behaviors]
internal class DenebRightAscension
{
It should_have_20_hours_ = () => UUT.Degrees.ShouldEqual(20u);
It should_have_41_minutes = () => UUT.Minutes.ShouldEqual(41u);
It should_have_59_seconds = () => UUT.Seconds.ShouldEqual(59u);
protected static Bearing UUT;
}
[Subject(typeof(HourAngle), "sexagesimal")]
internal class when_converting_hour_angle_to_sexagesimal
{
Because of = () =>
{
RaDeneb = 20.6999491773451;
UUT = new Bearing(RaDeneb);
};
Behaves_like<DenebRightAscension> deneb;
protected static Bearing UUT;
static double RaDeneb;
}
[Subject(typeof(Bearing), "sexagesimal")]
internal class when_converting_to_sexagesimal
{
Because of = () =>
{
RaDeneb = 20.6999491773451;
UUT = new Bearing(RaDeneb);
};
Behaves_like<DenebRightAscension> deneb;
protected static Bearing UUT;
static double RaDeneb;
}
请注意,行为字段按名称匹配,而不是任何类型的继承。所以这种行为神奇地知道我的意思是&UUT&#39;即使这些课程没有任何关系。