单元测试 C# 属性

发布于 2024-11-05 12:06:41 字数 428 浏览 0 评论 0原文

我正在处理一个具有很多属性的类。例如;

public class Bib
{        
    public int PartQty { get; set; }
}

现在进行单元测试;我做了像这里这样的 xUnit 测试

    [Fact]
    public void CanGetAndSetPartQuantity()
    {
        const int expected = 3;

        var target = new Bib() {PartQty = expected};

        Assert.Equal(expected, target.PartQty);
    }

,我讨厌我如何硬编码预期 = 3。测试访问器和变异器的此属性的好方法是什么?

I am working with a class that has lots of properties. For example;

public class Bib
{        
    public int PartQty { get; set; }
}

Now to unit test; I did the xUnit test something like

    [Fact]
    public void CanGetAndSetPartQuantity()
    {
        const int expected = 3;

        var target = new Bib() {PartQty = expected};

        Assert.Equal(expected, target.PartQty);
    }

here, I hate how I am hard-coding expected = 3. What's a good way to test this property for accessor and mutator?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

装迷糊 2024-11-12 12:06:41

由于该属性除了作为整数的 getter/setter 之外没有任何行为,因此您实际上只是在测试编译器是否正常工作。这对您的测试基本上没有任何价值。考虑完全删除它。这会让你摆脱这种奇怪的情况。 :)

如果您确实有一些想要捕获的行为(例如,允许的边界条件),您只需要测试这些行为,实际上不需要其他任何东西。通常,您将拥有作为对象一部分的边界条件常量。考虑使用这些常数,+/-一些适当的增量。

Since this property has no behavior other than being a getter/setter for an integer, you're essentially just testing that the compiler worked. This adds basically no value to your test. Consider removing it entirely. That would alleviate you of this odd situation. :)

If you do have some behavior you're trying to capture (e.g., allowed boundary conditions) you only need to test those, and really nothing else. Usually you will have constants for those boundary conditions available as part of the object. Consider using those constants, +/- some appropriate increment.

绝不服输 2024-11-12 12:06:41

约束非确定性非常适合这种单元测试。像这样写:

[Fact]
public void CanGetAndSetPartQuantity()
{
    const int expected = new Random().Next();

    var target = new Bib() {PartQty = expected};

    Assert.Equal(expected, target.PartQty);
}

这可以确保输出正确地表示输入,无论输入是什么。

Constrained Non-determinism is a good fit for this kind of unit test. Write it like this instead:

[Fact]
public void CanGetAndSetPartQuantity()
{
    const int expected = new Random().Next();

    var target = new Bib() {PartQty = expected};

    Assert.Equal(expected, target.PartQty);
}

This ensures that the output correctly represents the input, no matter what the input is.

生活了然无味 2024-11-12 12:06:41

我坚信单元测试是“白盒”测试,这意味着您可以使用已知的极端情况来选择测试输入。在这种特殊情况下,如果您信任您的编译器,则对于自动属性,测试是不必要的。如果您不能相信编译器会按照您期望的方式实现自动属性,那么您也不能相信它会按照您编写的方式执行测试。

也就是说,如果您有一个更复杂的设置器,您将根据可能的失败情况选择输入。一些典型情况:

  • 验证 >= 0 的属性为负数
  • 其他验证失败
  • 极端边界情况,例如 Int.MaxValue,有时会在 setter 中触发溢出和意外行为
  • 应该通过验证的任意值(没有关于如何验证的真正指导)在这里选择一个值,只要您知道它适合您的“好”情况即可。)

I'm a firm believer in having unit tests be 'white-box' tests, which means you are allowed to use known corner cases to choose your test inputs. In this particular, case, with an auto-property, the test is unnecessary if you trust your compiler. If you can't trust the compiler to implement an auto-property the way you expect, then you can't trust it to execute the test as you've written, either.

That said, if you have a more complex setter, you would choose your inputs based on the possible failure cases. A few typical cases:

  • Negative numbers for properties that validate >= 0
  • Other validation failures
  • Extreme boundary cases like Int.MaxValue which can sometimes trigger overflows and unexpected behavior in the setter
  • An arbitrary value that should pass validation (no real guidance on how to choose a value here, as long as you know it's in your 'good' case.)
雪花飘飘的天空 2024-11-12 12:06:41

这应该有帮助...

[Fact]     
public void CanGetAndSetPartQuantity()     
{
    bool fail = false;
    int expected = 0;

    while (!fail && expected < int.MaxValue)
    {
        var target = new Bib() {PartQty = expected};          
        fail = expected != target.PartQty;
        expected++;
    }

    Assert.IsTrue(!fail);
} 

This should help...

[Fact]     
public void CanGetAndSetPartQuantity()     
{
    bool fail = false;
    int expected = 0;

    while (!fail && expected < int.MaxValue)
    {
        var target = new Bib() {PartQty = expected};          
        fail = expected != target.PartQty;
        expected++;
    }

    Assert.IsTrue(!fail);
} 
七禾 2024-11-12 12:06:41

不久前,我观看了关于良好单元测试实践的演示(抱歉,我忘记了那个人的名字)。他主张使用精心选择的名称来存储类似常量的值。

在您的情况下,我会使用像这样的名称

const int SomeRandomValidPartQuantity=3;

,您表示有意使用该值,在这种情况下,您就在任何有效数量之后。

I wathced a presentation on good unit testing practices a while ago (sorry but the name of the guy escaped my fragile memory). He advocated the use of storing values like that in constants with carefully selected names.

In your case, I would use a name like

const int SomeRandomValidPartQuantity=3;

By this, you signal the intention of using exactly this value, and in this case you are just after any valid quantity.

我ぃ本無心為│何有愛 2024-11-12 12:06:41

测试应该源自某种用例。有趣的是,你首先介绍了你的课程,然后谈论编写测试,这倒退到了 TDD。

用例通知测试,测试通知代码。我非常怀疑您的用例是“我的 API 的用户可以将名为 PartQty 的属性设置为任何整数,并始终取回他们设置的整数”。如果这是真实的用例,您将编写一个单元测试来检查 int.MaxValueint.MinValue。然而,这些很少是现实世界的价值观。

真实世界的用例可能如下所示:“我的 API 消息的用户在 Bib 上注入 IFlugleBinder,将 PartQty 设置为 4然后调用 Execute 方法,这将调用 IFlugleBinder 实例上的 Bind 方法 4 次。”如果这是用例,您的测试看起来会非常不同。

老实说,Bib 看起来只是某种 DTO。根据我的经验,大多数 DTO 只是某些更高级别用例的产物。如果 DTO 作为 API 提供的函数调用的某些结果返回,那么您实际上应该返回一个接口,并且 DTO 类本身应该是私有的,在这种情况下,不需要显式测试它(只需测试属性从方法调用中获得的实际结果)。同样,如果它是从未公开的内部 DTO,则不要将其公开。如果您的用户必须提供一些值,那么您的 API 应该接受一个接口。让用户定义自己的实现该接口的类,或者提供一个不可变的类,如下所示:

public class Bib : IBib
{
    public Bib(int partQty)
    {
        PartQty = partQty;
    }
    public int PartQty { get; private set; }
}

然后,如果您想学究气,您可以编写一个测试来检查您的构造函数是否有效,但这并不那么重要。

The test should be derived from some kind of use case. The funny thing is that first you introduced your class, then talked about writing a test, which is backwards to TDD.

The use case informs the test, which informs the code. I highly doubt your use case is "the user of my API can set a property called PartQty to any integer and always get back the integer they set". If that were the real use case, you'd write a unit test that checks int.MaxValue and int.MinValue. However, these are rarely real-world values.

A real-world use case might look like: "the user of my API news up a Bib injecting an IFlugleBinder, sets the PartQty to 4 and then calls the Execute method. This calls the Bind method on the IFlugleBinder instance 4 times." If that was the use case, your test would look very different.

Honestly it looks like Bib is just a DTO of some kind. In my experience, most DTO's are just an artifact of some higher level use case. If the DTO is returned as some result of a function call that your API provides, then you should really be returning an interface, and the DTO class itself should be private, in which case it's not necessary to test it explicitly (just test the properties of the actual result you get from the method call). Likewise, if it's an internal DTO that's never exposed, then don't make it public. If your user has to provide some bundle of values, then your API should be accepting an interface. Let the user define their own class that implements the interface, or provide an immutable one, like this:

public class Bib : IBib
{
    public Bib(int partQty)
    {
        PartQty = partQty;
    }
    public int PartQty { get; private set; }
}

Then you can write a test that checks if your constructor works if you want to be pedantic, but it's not that important.

岁吢 2024-11-12 12:06:41

虽然我也相信这属于“测试直到无聊”类别,但如果您确实觉得这值得测试,那么批准测试提供了一种非常简单的测试方法。附件是一个简单的测试来检查属性。

[TestMethod]
[UseReporter(typeof(DiffReporter))]
public void TestMethod1()
{
    var fred = new Person{
            Age = 35,
        FirstName = "fred",
        LastName = "Flintstone",
        Hair = Color.Black
           };
    Approvals.Verify(fred.WritePropertiesToString());
}

这将生成一个文件,内容如下:

Person
{
    Age: 35
    FirstName: fred
    LastName: Flintstone
    Hair: Color [Black]
}

只需将该文件重命名为 .approved 即可完成。

请注意扩展方法的使用: .WritePropertiesToString()

这里有一个关于

MsTest 批准测试基础知识的视频: http://www.youtube.com/watch?v=bg8GOmlwqYY

Nunit:http://www.youtube.com/watch?v=aO_fyZBxaFk

Xunit:http://www.youtube.com/watch?v=8wPx0O4gFzc

While I also believe this falls under the "Test till bored" category, if you indeed feel this is worth testing, approval tests offers a very simple way to test. Attached is a simple test to check properties.

[TestMethod]
[UseReporter(typeof(DiffReporter))]
public void TestMethod1()
{
    var fred = new Person{
            Age = 35,
        FirstName = "fred",
        LastName = "Flintstone",
        Hair = Color.Black
           };
    Approvals.Verify(fred.WritePropertiesToString());
}

This will produce a file that reads:

Person
{
    Age: 35
    FirstName: fred
    LastName: Flintstone
    Hair: Color [Black]
}

Simply rename that file to .approved and you're done.

Note the use of the extension method: .WritePropertiesToString()

There a video about the basics of approval tests here for

MsTest: http://www.youtube.com/watch?v=bg8GOmlwqYY

Nunit: http://www.youtube.com/watch?v=aO_fyZBxaFk

Xunit: http://www.youtube.com/watch?v=8wPx0O4gFzc

我的奇迹 2024-11-12 12:06:41

您也可以使用 autofixture autodata 属性,如下所示:

        [Theory]
        [AutoData]
        public void CanGetAndSetPartQuantity(int expected)
        {
            var target = new Bib() {PartQty = expected};

            Assert.Equal(expected, target.PartQty);
        }

also you can use autofixture autodata attribute like this:

        [Theory]
        [AutoData]
        public void CanGetAndSetPartQuantity(int expected)
        {
            var target = new Bib() {PartQty = expected};

            Assert.Equal(expected, target.PartQty);
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文