BD#for C#NUnit

mje*_*zzi 10 c# bdd nunit

我一直在使用家庭酿造的BDD Spec扩展来在NUnit中编写BDD样式测试,我想看看每个人都在想什么.它增加了价值吗?真是太糟糕了?如果是这样的话?那里有更好的东西吗?

这是源:https: //github.com/mjezzi/NSpec

我创建这个有两个原因

  1. 使我的测试易于阅读.
  2. 生成普通英语输出以查看规范.

以下是测试外观的示例:

- 这些天僵尸似乎很受欢迎..

鉴于Zombie,Peson和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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

而NSpec风格的测试:

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 ) );
    }
}
Run Code Online (Sandbox Code Playgroud)

您将在输出窗口中获得Spec输出:

[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).
Run Code Online (Sandbox Code Playgroud)

Lun*_*ore 10

我将调用BDD的一些用途,而不仅仅是框架,因为我认为对单元级BDD有一个非常好的理解可能会影响你创建的一些东西.总的来说,我喜欢它.开始:

而不是要求他们PersonAttacksZombieTests,我只是打电话给他们PersonTests,甚至PersonBehaviour.通过这种方式查找与特定类关联的示例变得更加容易,可以将它们用作文档.

它看起来不像IsStillAlive是你想要在某个人身上设置的那种东西; 而是一种内在的属性.小心这样公开的事情.您正在添加不需要的行为.

通话new Person(null)似乎并不特别直观.如果我想创造一个没有武器的人,我通常会寻找一个构造函数new Person().BDD的一个好方法就是编写你想要的API,然后让下面的代码做好工作 - 使代码易于使用,而不是易于编写.

我的行为和责任似乎有点奇怪.为什么这个人而不是僵尸负责确定该人的生命或死亡?我更愿意看到这样的行为:

  • 一个人可以配备武器(通过person.Equip(IWeapon weapon)).
  • 如果一个人没有武器就会以拳头开始.
  • 当该人攻击僵尸时,该人使用僵尸上的武器.
  • 武器决定了僵尸的生命或死亡.
  • 如果僵尸还活着,它会反击.僵尸会杀死这个人(通过person.Kill).

在我看来,好像它在更好的地方有行为和责任.使用不同类型的武器进行无用的攻击,而不是检查null,也可以避免使用该if语句.你需要不同的测试:

  • 使用它时,拳头不应该杀死僵尸
  • 使用电锯时,电锯会杀死一个僵尸
  • 攻击僵尸时,一个人应该使用装备好的武器
  • 如果没有其他武器,一个人应该配备拳头
  • 僵尸应该在它还活着的时候进行攻击.
  • 僵尸如果死了就不应该反击.
  • 如果被杀,僵尸应该死亡.
  • 如果被杀,一个人应该死

除此之外,它看起来很棒.我喜欢你使用模拟的方式,字符串的流动以及测试方法本身的措辞.我也很喜欢ProveBy; 它完全按照它在锡上所说的那样做,很好地将提供行为示例和运行它们作为测试之间的区别.


Dmi*_*ruk 2

我的问题是与"something".ProveBy()稍后显示的文本不匹配(“当......它应该......”)。我认为BDD的理念是让测试措辞和测试报告尽可能保持相似。