C#NUnit的BDD [英] BDD for C# NUnit
问题描述
我一直在使用自制的BDD Spec扩展来在NUnit中编写BDD样式测试,我想看看每个人的想法.它会增加价值吗?是吸吗?如果可以,为什么?还有更好的东西吗?
I've been using a home brewed BDD Spec extension for writing BDD style tests in NUnit, and I wanted to see what everyone thought. Does it add value? Does is suck? If so why? Is there something better out there?
以下是来源: https://github.com/mjezzi/NSpec
创建此文件有两个原因
- 使我的测试易于阅读.
- 产生简单的英语输出到 查看规格.
- To make my tests easy to read.
- To produce a plain english output to review specs.
这是一个测试外观的示例:
Here's an example of how a test will look:
-因为僵尸现在似乎很流行..
-since zombies seem to be popular these days..
给出僵尸,佩森和IWeapon:
Given a Zombie, Peson, and IWeapon:
namespace Project.Tests.PersonVsZombie
{
public class Zombie
{
}
public interface IWeapon
{
void UseAgainst( Zombie zombie );
}
public class Person
{
private IWeapon _weapon;
public bool IsStillAlive { get; set; }
public Person( IWeapon weapon )
{
IsStillAlive = true;
_weapon = weapon;
}
public void Attack( Zombie zombie )
{
if( _weapon != null )
_weapon.UseAgainst( zombie );
else
IsStillAlive = false;
}
}
}
以及NSpec样式的测试:
And the NSpec styled tests:
public class PersonAttacksZombieTests
{
[Test]
public void When_a_person_with_a_weapon_attacks_a_zombie()
{
var zombie = new Zombie();
var weaponMock = new Mock<IWeapon>();
var person = new Person( weaponMock.Object );
person.Attack( zombie );
"It should use the weapon against the zombie".ProveBy( spec =>
weaponMock.Verify( x => x.UseAgainst( zombie ), spec ) );
"It should keep the person alive".ProveBy( spec =>
Assert.That( person.IsStillAlive, Is.True, spec ) );
}
[Test]
public void When_a_person_without_a_weapon_attacks_a_zombie()
{
var zombie = new Zombie();
var person = new Person( null );
person.Attack( zombie );
"It should cause the person to die".ProveBy( spec =>
Assert.That( person.IsStillAlive, Is.False, spec ) );
}
}
您将在输出窗口中获得Spec输出:
You'll get the Spec output in the output window:
[PersonVsZombie]
- PersonAttacksZombieTests
When a person with a weapon attacks a zombie
It should use the weapon against the zombie
It should keep the person alive
When a person without a weapon attacks a zombie
It should cause the person to die
2 passed, 0 failed, 0 skipped, took 0.39 seconds (NUnit 2.5.5).
推荐答案
我将介绍BDD的一些用途,而不仅仅是框架,因为我认为对单元级BDD的真正了解可能会影响一些您创建的东西.总的来说,我喜欢它.去吧:
I'm going to call out some uses of BDD rather than just the framework, as I think having a really great understanding of unit-level BDD might affect some of the things you create. Overall, I like it. Here goes:
我不称它们为PersonAttacksZombieTests
,而是称它们为PersonTests
,甚至称PersonBehaviour
.这样可以更轻松地查找与特定类关联的示例,让您将其用作文档.
Rather than calling them PersonAttacksZombieTests
, I'd just call them PersonTests
or even PersonBehaviour
. It makes it much easier to find the examples associated with a particular class this way, letting you use them as documentation.
看起来不像IsStillAlive
是您想放在人身上的那种东西;而是一种固有属性.小心地将此类内容公开.您正在添加不需要的行为.
It doesn't look like IsStillAlive
is the kind of thing you'd want to set on a person; rather an intrinsic property. Careful making things like this public. You're adding behaviour that you don't need.
调用new Person(null)
似乎不是特别直观.如果我想创建一个没有武器的人,通常我会寻找一个构造器new Person()
.使用BDD的一个好技巧是编写所需的API,然后使下面的代码完成艰苦的工作-使代码易于使用,而不是易于编写.
Calling new Person(null)
doesn't seem particularly intuitive. If I wanted to create a person without a weapon, I would normally look for a constructor new Person()
. A good trick with BDD is to write the API you want, then make the code underneath do the hard work - make code easy to use, rather than easy to write.
我的行为和责任也显得有些奇怪.为什么要由该人而不是僵尸负责确定该人是死还是死?我希望看到这样的行为:
The behaviour and responsibilities also seem a bit odd to me. Why is the person, and not the zombie, responsible for determining whether the person lives or dies? I'd prefer to see behaviour like this:
- 一个人可以装备武器(通过
person.Equip(IWeapon weapon)
). - 如果没有武器,一个人会从拳头开始.
- 当人袭击僵尸时,他会在僵尸身上使用武器.
- 武器决定僵尸是死还是死.
- 如果僵尸还活着,它将发起攻击.僵尸将杀死该人(通过
person.Kill
).
- A person can be equipped with a weapon (via
person.Equip(IWeapon weapon)
). - A person starts with a fist if they have no weapon.
- When the person attacks a zombie, the person uses the weapon on the zombie.
- The weapon determines whether the zombie lives or dies.
- If the zombie is still alive, it attacks back. The zombie will kill the person (via
person.Kill
).
在我看来,这似乎是行为和责任得到更好的解决.使用另一种武器进行无用攻击,而不是检查是否为空,也可以避免使用if
语句.您需要进行不同的测试:
That seems to me as if it's got the behaviour and responsibilities in a better place. Using a different kind of weapon for useless attacks, rather than checking for null, also allows you to avoid that if
statement. You'd need different tests:
- 用拳头杀死僵尸
- 用电锯对付僵尸应该杀死它
- 一个人在攻击僵尸时应该使用装备精良的武器
- 如果没有其他武器,一个人应该装备拳头
- 僵尸还活着时应该反击.
- 僵尸死后不应该回击.
- 僵尸如果被杀应该会死.
- 一个人如果被杀应该死.
除此之外,它看起来很棒.我喜欢您使用模拟的方式,字符串流以及测试方法本身的措词.我也很喜欢ProveBy
;它的功能完全与表面上所说的一样,并且很好地捆绑了提供行为示例和将其作为测试运行之间的区别.
Other than that, it looks great. I like the way you've used the mocks, the flow of strings, and the phrasing of the test methods themselves. I also quite like ProveBy
; it's doing exactly what it says on the tin, and nicely ties up the difference between providing examples of behaviour and running them as tests.
这篇关于C#NUnit的BDD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!