C#NUnit的BDD [英] BDD for C# NUnit

查看:102
本文介绍了C#NUnit的BDD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用自制的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

创建此文件有两个原因

  1. 使我的测试易于阅读.
  2. 产生简单的英语输出到 查看规格.
  1. To make my tests easy to read.
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆