使用单元测试的 C# 变量

c# variables with unit testing

提问人:Ouckahs 提问时间:10/18/2023 最后编辑:Dave CousineauOuckahs 更新时间:10/18/2023 访问量:92

问:

我是单元测试的新手,所以我正在尝试一些基本程序来测试它。如果我创建了一个带有私有变量的类并声明了两个函数,那么第二个函数是否有办法访问更新变量的值?在下面的示例中,当我在单元测试中调用临时函数时,在 add 函数之后,它返回 0(初始值),而不是添加到存储的任何内容的更新值。有没有办法在这里返回更新后的值?

// Class scope variable
Private int storage = 0;

Public int Storage
{
   get { return storage; }
   set { storage = value; }
}
Public void add(int pass)
{
   Storage += pass;
}

Public int temp (){
   return Storage;
}
// Testing 
namespace TestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void Adding_Storage()
        {
            Class1 class1 = new Class1();

            class1.add(5);
            int result = testing.temp();
            Assert.AreEqual(5, result);  

        }

        [TestMethod]
        public void Display_Storage()
        {
            Class1 class1 = new Class1();

            class1.temp();
            int result = class1.temp();
            Assert.AreEqual(0, result);
  
            // this is where I would like result to return 5,
            // but it still returns 0.
        }
C# MSTest

评论

0赞 Chris Schaller 10/18/2023
是的,但根据您的单元测试框架,它略有不同,请在您使用的框架中包含您的测试用例和标签。我想我明白你的意思,但我们需要这种明确性,让更广泛的社区参与讨论
0赞 Ouckahs 10/18/2023
包括。这是 .Net 框架 4.7.2
0赞 stuartd 10/18/2023
在第二个测试中,您创建了一个新的,并且从不调用,因此该值为零。Class1add()
0赞 stuartd 10/18/2023
不清楚你为什么要使用这种方法,而不仅仅是测试?temp()Storage
2赞 Enigmativity 10/18/2023
请发布真实代码。关键字中有大写字母。

答:

1赞 Chris Schaller 10/18/2023 #1

问题在于,您正在每个测试中创建测试目标类的新实例。

理想情况下,对于每个测试用例,应首先设置前提条件,应避免在当前测试用例中使用先前测试的输出。因此,使用遗嘱可能会为您提供解决方案,这样做不是一个好主意。它是一种反模式。[TestInitialize]

在显示存储中,应在测试之前设置已知状态:

    [TestMethod]
    public void Display_Storage()
    {
        // setup the pre-conditions for this specific test case
        Class1 class1 = new Class1();
        int expectedResult = 5;
        class1.add(expectedResult);

        // this is the behaviour this method is testing
        int result = class1.temp();
        Assert.AreEqual(expectedResult, result);
    }

您可以设置一个在测试之间共享的通用实例,但这很快就会导致问题和泄漏测试......在此处阅读有关 \[TestInitialize\] 的更多信息,但保留此内容以初始化静态或不可变资源。Class1

如果您的测试依赖于其他测试的结果,那么测试的执行顺序对于测试是否通过至关重要。这实际上使测试和审查测试用例变得更加困难。

测试的重点是验证功能。您可以进行一个测试来验证对象是否保留状态,然后在其他测试中,我们假设状态保留是可信的(即依赖测试用例),并专注于测试该测试用例的行为。

为了解释,看看你的第一个测试,它验证了它是否有效。现在,我们不需要验证其他测试的结果,其程度与第一次测试相同。我们可以简单地使用该方法。add(int)add(int)

  • 您的第一个测试确实应该涵盖边界条件和已知故障点,至少它应该测试通过和。但这不是代码审查......Int32.MaxValueInt32.MinValue

如果第一个测试失败,那么第二个测试也会失败,但这是意料之中的,但现在如果你只独立运行第二个测试,它就可以通过,而不会强迫测试人员也首先测试第一个情况。

我们不需要验证在第二个测试中是否特别有效,但我们应该使用这些依赖方法调用来帮助在测试人员只测试单个测试用例的情况下发现问题。.add()

评论

0赞 Greg Burghardt 10/25/2023
我喜欢这个答案,但我不同意这种情况的反模式。它可能不是需要最少代码的解决方案,但它会起作用并且易于维护。我真正喜欢你的答案只是添加第二个断言。我们经常忘记我们正在测试行为和需求。在一个单元测试中,多个断言是可以的,只要它们是有凝聚力的。我认为它们在 OP 的案例中是有凝聚力的。[TestInitialize]
0赞 Chris Schaller 10/25/2023
您需要小心,因为它很容易陷入创建顺序依赖测试用例的陷阱。 在这种情况下,您将在初始化逻辑中放入所有内容,因此我们使用[TestInitialize]new Class1()[TestInitialize]
0赞 SmellyCat 10/18/2023 #2

有没有办法让第二个 [test] 访问更新变量的值?

是的,您可以在 的作用域中实例化,而不是实例化局部变量。但是,您可能不想这样做。Class1UnitTest1

设计测试有三种方法:

  • 将所有变量声明为局部变量:这样做的好处是,在测试结束时,它们都会被清理干净。
  • 在类范围内声明一些变量。确保在使用 MSTest 和方法的测试之间重置其值。每个单独的测试都不应影响后续测试。测试的运行顺序不应影响测试是否通过。setUptearDown
  • 在测试之间共享变量,以便每个测试用例方法实际上是较长测试的一部分。测试的运行顺序会影响测试是否通过,您需要深入了解自己的代码才能诊断测试失败的原因。有些人在长时间测试(超过 10 分钟)时采用这种方法,但很少可取。

如果你刚刚开始,你应该更喜欢第一种方法。随着您越来越熟悉,您可以尝试第二种方法。您无需尝试第三种方法。

如果确实需要以类似的方式初始化多个测试的变量,则始终可以在执行测试之前创建一个执行初始化的共享方法。