如何在TestDriven.NET中指定测试方法的参数?

12

我正在使用NUnit和TestDriven.NET插件编写单元测试。我想给一个测试方法提供参数,如下所示:

[TestFixture]
public class MyTests
{
    [Test]
    public void TestLogin(string userName, string password)
    {
        // ...
    }

    ...
}
正如您所见,这些参数是私有数据,因此我不想将它们硬编码或放在文件中。实际上,我希望在每次运行测试时都会提示我,而不需要任何地方编写它们。
当我尝试运行此测试时,输出窗口显示以下消息:
“未执行TestCase 'MyProject.MyTests.TestLogin':未提供参数”
因此,我的问题是如何提供这些参数?我期望TestDriven.NET显示提示,以便我可以输入值,但它没有...
抱歉如果我的问题看起来很蠢,答案可能非常简单,但我在Google上找不到任何有用的信息...
编辑:我刚刚找到了一种方法,但这是一个骯髒的技巧...
    [Test, TestCaseSource("PromptCredentials")]
    public void TestLogin(string userName, string password)
    {
        // ...
    }

    static object[] PromptCredentials
    {
        get
        {
            string userName = Interaction.InputBox("Enter user name", "Test parameters", "", -1, -1);
            string password = Interaction.InputBox("Enter password", "Test parameters", "", -1, -1);
            return new object[]
            {
                new object[] { userName, password }
            };
        }
    }

我仍然对更好的解决方案感兴趣...


3
如果你这样做,将会在 CI(持续集成)环境中自动运行测试时遇到问题。 - 7wp
你说得完全正确。然而,这是一个小型社区项目,所以CI目前并不是真正的问题。 - Thomas Levesque
5个回答

22

使用TestCase属性。

[TestCase("User1", "")]
[TestCase("", "Pass123")]
[TestCase("xxxxxx", "xxxxxx")]
public void TestLogin(string userName, string password)
{
    // ...
}

2
+1。这种方法比选择的答案要好得多,因为它可以在TestCase()参数中正确处理依赖注入,而不是机械地重复“方法中没有参数”的说法。不幸的是,我认为MS Unit Test没有类似于这样的功能,只有Nunit。 - DeepSpace101
2
这是正确且简短的答案。无论这是否是一个好或坏的实践都不重要。 - Mário Meyrelles
请将此标记为正确答案。这回答了问题,对我来说在一般情况下使用参数并不是坏的做法。但对于密码,我会更加谨慎。 - Rexxo

2

我认为你可以使用NUnit的RowTest插件来解决这个问题,插件下载链接在这里

你可以创建简单的数据驱动测试,其中测试数据由[Row]属性提供。以下是一个使用不同参数反复运行的测试示例:

[TestFixture]
public class RowTestSample
{
 [RowTest]
 [Row( 1000, 10, 100.0000)]
 [Row(-1000, 10, -100.0000)]
 [Row( 1000, 7, 142.85715)]
 [Row( 1000, 0.00001, 100000000)]
 [Row(4195835, 3145729, 1.3338196)]
 public void DivisionTest(double numerator, double denominator, double result)
 {
    Assert.AreEqual(result, numerator / denominator, 0.00001);
 }
} 

啊,好的。我误解了。不过知道TestCaseAttribute还是很不错的 :) - 7wp

2

单元测试通常不应该带任何参数。你需要在测试中创建必要的数据。

  • 期望值
  • 你调用想要测试的方法并传递必要的参数
  • 你将结果与期望值和被测试方法返回的值进行比较

MS Unit 测试不允许向测试中传递参数。相反,您需要创建数据驱动的单元测试。尝试点击链接,它可能会对您有所帮助。

正如我所提到的,我认为将参数传递给单元测试本身并不是好的实践。


更新: 我当时太年轻了 :). 请考虑Sarfraz的答案,了解如何向NUnit测试传递参数。


1
谢谢,但是这并没有解决我的问题...我该如何运行一个需要凭据的测试呢?我不想把我的个人用户名和密码放在与他人共享的代码中... - Thomas Levesque
在这种情况下,请使用虚拟凭据。你的单元测试应该涵盖什么样的逻辑,以至于需要处理凭据等内容? - Juri
哦,我现在看到了你编辑过的帖子。你不能只使用一些虚拟凭证吗?一个测试用户+密码,该用户有权访问你需要实现的内容?虽然我不太确定你想要达到的目标是否真的适合通过单元测试来测试。请参考:https://dev59.com/THM_5IYBdhLWcg3wt1rD#1369982 - Juri
我正在测试的组件连接到VBulletin论坛以检索身份验证Cookie。也许我可以创建一个虚拟账户...或者也许你是对的,这甚至不应该是单元测试 ;) - Thomas Levesque
1
理解...嗯,关于什么是单元测试,这个总是有一些“讨论”的余地。在你的情况下,我会说这并不是我会用单元测试来捕捉的东西。我会做的是提供一个虚拟认证cookie,并以某种方式注入它,以模拟对VBulletin的调用。通过这种方法,我可以测试我的逻辑在正确的cookie和错误的cookie下的行为。在我看来,这才是应该通过单元测试来捕捉的内容。 - Juri
1
Juri和J.R. Garcia是正确的。你想要无人值守、自动化的测试 - 这样你就可以从构建服务器等地方运行它们。实现这一点的方法是使用依赖注入,使用一个处理身份验证的虚拟(存根)对象。在实际应用中,你注入真正的身份验证方案(实现相同接口)。 - TrueWill

0
创建一个类并将所需变量的详细信息存储在const中。 注意:如果您将变量创建为静态变量,则它在Nunit框架中将无法工作。
public Class Credential
{
    public const string PUBLIC_USER = "PublicUser@gmail.com";
    public const string PASSWORD= "password123";
}

[Test]
[TestCase(Credential.PUBLIC_USER, Credential.PASSWORD)]
public void VerifyLogin(string username, string password)
 

0

我同意其他答案的观点,传递参数可能不是最佳实践,但硬编码凭据或服务器地址也不是。这些信息在某些时候可能会发生变化。

受问题中建议解决方案的启发,我只需读取控制台输入而不是使用输入框。参数保存在文件中。在开始测试时,该文件被重定向并从一些初始化函数中读取,该函数应在运行任何测试用例之前调用。

nunit tests.dll < test.config

这样可以避免用户交互,并且可以由任何自动化脚本运行。缺点是密码仍然必须保存在某个地方,但至少可以在测试人员的本地机器上保存并且很容易更改。

这是为一个项目而设计的,该项目使用包含测试用例的 Excel 表格(不是单元测试)让其他人为一个更大的服务器端项目创建测试用例,而不需要更改任何代码。如果所有测试用例都被强制放在一个巨大的 Excel 表格中,那将是不好的。此外,没有 CI,只是许多在不同服务器上的测试环境。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接