gpt4 book ai didi

c# - C# NUnit 的 BDD

转载 作者:可可西里 更新时间:2023-11-01 09:02:27 25 4
gpt4 key购买 nike

我一直在使用自制的 BDD 规范扩展在 NUnit 中编写 BDD 风格的测试,我想看看每个人的想法。它能增加值(value)吗?很烂吗?如果是,为什么?那里有更好的东西吗?

这是来源: 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;
}
}
}

以及 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 ) );
}
}

您将在输出窗口中获得规范输出:

[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 的真正深入理解可能会影响您创建的某些内容。总的来说,我喜欢它。开始了:

我不称它们为 PersonAttacksZombieTests,而是称它们为 PersonTests 甚至 PersonBehaviour。通过这种方式可以更轻松地找到与特定类关联的示例,让您可以将它们用作文档。

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

调用 new Person(null) 似乎不是特别直观。如果我想创建一个没有武器的人,我通常会寻找构造函数 new Person()。 BDD 的一个好技巧是编写您想要的 API,然后让下面的代码完成艰苦的工作 - 让代码易于使用,而不是易于编写。

行为和责任对我来说也有点奇怪。为什么是人而不是僵尸来决定人的生死?我更愿意看到这样的行为:

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

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

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

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

关于c# - C# NUnit 的 BDD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4706968/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com