我喜欢 mspec。它非常适合以易于与非技术人员沟通的方式提供关键示例,但有时我发现它提供了不必要的冗长内容,特别是类的爆炸式增长。
看下面的例子。
我想模拟国际象棋中马棋子的运动。假设骑士不靠近任何其他棋子或棋盘边界,那么骑士可以有 8 种可能的 Action ,我想涵盖这些可能性中的每一种,但坦率地说,我懒得编写 8 个单独的规范(8 个类别)。我知道我可以很聪明地处理行为和继承,但是当我想涵盖 8 个有效的 Action 时,我不知道如何在没有 8 个因为
的情况下做到这一点,因此因此需要 8 个单独的类。
使用 mspec 覆盖这些场景的最佳方法是什么?
一些代码。
public class Knight
{
public string Position {get; private set;}
public Knight(string startposition)
{
Position = startposition;
}
public void Move
{
// some logic in here that allows a valid move pattern and sets positions
}
}
我可能会做什么。
[Subject(typeof(Knight),"Valid movement")]
public class when_moving_the_knight
{
Establish that = () => knight =new Knight("D4");
Because of = ()=> knight.Move("B3");
It should_update_position = ()=> knight.Position.ShouldEqual("B3");
It should_not_throw;
/// etc..
}
但不是 8 次。
最佳答案
老实说,我无法告诉您在 MSpec 中做到这一点的最佳方法。但当我在类似的情况下使用 MSpec 时,我遇到了类似的类爆炸问题。不知道大家有没有尝试过RSpec。在 RSpec 中,上下文和规范是在可执行代码的范围内构建的。这意味着您可以创建一个数据结构,对其进行迭代,并使用一个代码块创建多个上下文和规范。当您试图指定基于数学的事物的行为方式(质因数、井字棋、国际象棋等)时,这变得特别方便。可以在一组给定值和预期值的每个成员中指定单一的行为模式。
此示例是用 NSpec 编写的,NSpec 是一个以 RSpec 为模型的 C# 上下文/规范框架。我故意留下了一个失败的规范。我只是沿着这个套路走得足够远,找到了使用迭代的地方。失败的规范迫使您解决简单实现的缺点。
这是素因子型的另一个例子:http://nspec.org/#dolambda
输出:
describe Knight
when moving 2 back and 1 left
when a knight at D4 is moved to B3
knight position should be B3
when a knight at C4 is moved to A3
knight position should be A3 - FAILED - String lengths are both 2. Strings differ at index 0., Expected: "A3", But was: "B3", -----------^
**** FAILURES ****
describe Knight. when moving 2 back and 1 left. when a knight at C4 is moved to A3. knight position should be A3.
String lengths are both 2. Strings differ at index 0., Expected: "A3", But was: "B3", -----------^
at ChessSpecs.describe_Knight.<>c__DisplayClass5.<when_moving_2_back_and_1_left>b__4() in c:\Users\matt\Documents\Visual Studio 2010\Projects\ChessSpecs\ChessSpecs\describe_Knight.cs:line 23
2 Examples, 1 Failed, 0 Pending
代码:
using System.Collections.Generic;
using NSpec;
class describe_Knight : nspec
{
void when_moving_2_back_and_1_left()
{
new Each<string,string> {
{"D4", "B3"},
{"C4", "A3"},
}.Do( (start, moveTo) =>
{
context["when a knight at {0} is moved to {1}".With(start,moveTo)] = () =>
{
before = () =>
{
knight = new Knight(start);
knight.Move(moveTo);
};
it["knight position should be {0}".With(moveTo)] = () => knight.Position.should_be(moveTo);
};
});
}
Knight knight;
}
class Knight
{
public Knight(string position)
{
Position = position;
}
public void Move(string position)
{
Position = "B3";
}
public string Position { get; set; }
}
关于mspec - 在这种情况下,使用 MSpec 如何避免上下文/类爆炸?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5796655/