我一直在使用MSpec编写我的单元测试,并且非常喜欢BDD风格,我认为它更具可读性。我现在正在使用MSpec不支持的Silverlight,所以我不得不使用MSTest,但仍然希望保持BDD风格,所以我想尝试一种方法来做到这一点。
只是为了解释我想要实现的目标,这就是我如何编写MSpec测试
[Subject(typeof(Calculator))]
public class when_I_add_two_numbers : with_calculator
{
Establish context = () => this.Calculator = new Calculator();
Because I_add_2_and_4 = () => this.Calculator.Add(2).Add(4);
It should_display_6 = () => this.Calculator.Result.ShouldEqual(6);
}
public class with_calculator
{
protected static Calculator;
}
因此,使用MSTest,我会尝试编写这样的测试(尽管你可以看到它不会起作用,因为我已经输入了2个TestInitialize属性,但你得到了我正在尝试做的事情。)
[TestClass]
public class when_I_add_two_numbers : with_calculator
{
[TestInitialize]
public void GivenIHaveACalculator()
{
this.Calculator = new Calculator();
}
[TestInitialize]
public void WhenIAdd2And4()
{
this.Calculator.Add(2).Add(4);
}
[TestMethod]
public void ThenItShouldDisplay6()
{
this.Calculator.Result.ShouldEqual(6);
}
}
public class with_calculator
{
protected Calculator Calculator {get;set;}
}
有人能想出一些更优雅的建议来用MSTest以这种方式编写测试吗?
答案 0 :(得分:34)
你对这个问题的看法:
[TestClass]
public class when_i_add_two_numbers : with_calculator
{
public override void When()
{
this.calc.Add(2, 4);
}
[TestMethod]
public void ThenItShouldDisplay6()
{
Assert.AreEqual(6, this.calc.Result);
}
[TestMethod]
public void ThenTheCalculatorShouldNotBeNull()
{
Assert.IsNotNull(this.calc);
}
}
public abstract class with_calculator : SpecificationContext
{
protected Calculator calc;
public override void Given()
{
this.calc = new Calculator();
}
}
public abstract class SpecificationContext
{
[TestInitialize]
public void Init()
{
this.Given();
this.When();
}
public virtual void Given(){}
public virtual void When(){}
}
public class Calculator
{
public int Result { get; private set; }
public void Add(int p, int p_2)
{
this.Result = p + p_2;
}
}
答案 1 :(得分:2)
Mark Nijhof已an example在Fohjin.DDD github repository中使用NUnit进行Given-When-Then样式测试。
以下是上述示例的摘录:
public class When_registering_an_domain_event : BaseTestFixture<PreProcessor>
{
/* ... */
protected override void When()
{
SubjectUnderTest.RegisterForPreProcessing<ClientMovedEvent>();
SubjectUnderTest.Process();
}
[Then]
public void Then_the_event_processors_for_client_moved_event_will_be_registered()
{
IEnumerable<EventProcessor> eventProcessors;
EventProcessorCache.TryGetEventProcessorsFor(typeof(ClientMovedEvent), out eventProcessors);
eventProcessors.Count().WillBe(1);
}
}
你可以在base class implementation:
中看到给定的[Given]
public void Setup()
{
CaughtException = new NoExceptionWasThrownException();
Given();
try
{
When();
}
catch (Exception exception)
{
CaughtException = exception;
}
finally
{
Finally();
}
}
答案 2 :(得分:1)
我最近一直在提出这类问题。有很多合理的选择,你可以轻松创建自己的选项,如本文的一些答案中所示。我一直在研究BDD测试框架,目的是使其易于扩展到任何单元测试框架。我目前支持MSTest和NUnit。它被称为Given,它是开源的。基本思路非常简单,给出了常用功能集的包装器,然后可以为每个测试运行器实现。
以下是NUnit Given测试的示例:
[Story(AsA = "car manufacturer",
IWant = "a factory that makes the right cars",
SoThat = "I can make money")]
public class when_building_a_toyota : Specification
{
static CarFactory _factory;
static Car _car;
given a_car_factory = () =>
{
_factory = new CarFactory();
};
when building_a_toyota = () => _car = _factory.Make(CarType.Toyota);
[then]
public void it_should_create_a_car()
{
_car.ShouldNotBeNull();
}
[then]
public void it_should_be_the_right_type_of_car()
{
_car.Type.ShouldEqual(CarType.Toyota);
}
}
我尽力忠实于Dan North's Introducting BDD博客中的概念,因此,所有内容都是使用给定的,何时的,然后是规范的风格来完成的。它的实现方式允许你有多个givens甚至多个when,并且应按顺序执行(仍然检查这个)。
此外,还有一套完整的Should扩展包含在Given中。这样可以实现上面所见的ShouldEqual()
调用,但是有很多很好的方法可以进行集合比较和类型比较等。对于那些熟悉MSpec的人,我基本上将它们撕掉并进行了一些修改以使它们工作在MSpec之外。
此外,根据每个程序集的测试结果,使用t4模板创建HTML报告。具有匹配故事的类都嵌套在一起,并打印每个方案名称以供快速参考。对于上述测试,报告看起来像这样:
失败的测试将显示为红色,可以单击以查看异常详细信息。
这就是它。我在我正在研究的几个项目中使用它,所以它仍在积极开发中,但我将核心描述为非常稳定。我正在寻找一种通过组合而不是继承来共享上下文的方法,因此这可能是下一次改变派克的变化之一。引发批评。 :)
答案 3 :(得分:0)
您可以使用NUnit.Specifications并编写如下测试:
using NUnit.Specifications;
using Should;
public class OrderSpecs
{
[Component]
public class when_a_customer_places_an_order : ContextSpecification
{
static OrderService _orderService;
static bool _results;
static Order _order;
Establish context = () =>
{
_orderService = new OrderService();
_order = new Order();
};
Because of = () => _results = _orderService.PlaceOrder(_order);
It should_successfully_place_the_order = () => _results.ShouldBeTrue();
}
}
答案 4 :(得分:0)
MSTestEnhancer可能会对您有所帮助,您可以通过NuGet.org获取该套餐。
以下是示例代码:
[TestClass]
public class TheTestedClassTest
{
[ContractTestCase]
public void TheTestedMethod()
{
"When Xxx happens, results in Yyy.".Test(() =>
{
// Write test case code here...
});
"When Zzz happens, results in Www.".Test(() =>
{
// Write test case code here...
});
}
}
当你看到你的测试结果时,你会得到以下信息:
我写了一篇帖子来介绍它的更多信息。有关详细信息,请参阅Introducing MSTestEnhancer to make unit test result easy to read - walterlv。