如何在 C# 中为以下代码编写 nunit 测试用例?如何为没有参数的方法编写 nunit 测试用例?

How to write nunit test case for below code in c#? How ro write nunit test cases for methods with no arguments?

我如何编写单元测试(使用 nUnit)一个 class 在 c# 中有没有参数的方法? 我在 Program.cs 中调用这个 showinfo() 方法。我想为此编写一个 nunit 测试用例...但是由于它不包含任何参数,我该如何测试它?

 public void showInfo() //no arguments are passes here and im calling this in Program.cs
            {
                int indexNum;
                string inId = Convert.ToString(Console.ReadLine());//taking Id as input 
                Console.Write("Enter account Password :");
                string inPass = Convert.ToString(Console.ReadLine());//taking password

                if (myId.Contains(inId)&&myPass.Contains(inPass))
                {
                    Console.ForegroundColor= ConsoleColor.Green;
                    Console.WriteLine("Login Success!", Console.ForegroundColor);
                    Console.ResetColor();
                    indexNum = Array.IndexOf(myId, inId);

                    Console.WriteLine("Your details: ");
                    Console.WriteLine("Name: " + myName[indexNum]);
                    Console.WriteLine("Id: " + myId[indexNum]);
                    Console.WriteLine("Acc Type: " + myAccType[indexNum]);
                    Console.WriteLine("Date of Joining: " + myDob[indexNum]);
                    Console.WriteLine("Domain: " + myDomain[indexNum]);
                    Console.WriteLine("Manager: " + myManager[indexNum]);
                    //Console.WriteLine("Employee name: " + empl_name[indexNum]);
                    //Console.WriteLine(myId);
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Login Error!",Console.ForegroundColor);
                    Console.ResetColor();
                }
            }

有很多方法可以测试不带参数的方法、私有方法等。您只需要设置一些东西,这样当您测试您的方法时,它会调用另一个方法(带参数)

在您的 AssemblyInfo.cs 中,您添加了一个属性

#if DEBUG #then
InternalsVisibleTo("your test project")`.
#endif

在你想要测试的class中做这样的事情

public class A
{
#if DEBUG #then
    private MethodParameters _testParameters

    internal void SetMethodParameters(MethodParameters testParameters)
    {
        _testParameters = testParameters
    }
#endif
    public void NoArgumentMethod()
    {
#if DEBUG #then
        if (_testParameters)
        {
            PrivateArgumentMethod(_testParameters);
            return;
        }
#endif 
        // collect your arguments here and pass to private method
        var mp = new MethodParameters();
        mp.Id = _someId;
        // . . . . . 
    }

    private void PrivateArgumentMethod(MethodParameters testParameters)
    {
         // execute here
    }

    internal class MethodParameters
    {
        public int Id {get; set;}
        // more properties here
    }
}

如您所见,这非常令人费解。这还有其他变体。最重要的是 - 您可能注意到您需要在 DEBUG 模式下编译和 运行 单元测试,以便某些代码可用于单元测试但不能用于发布程序集。为此使用条件编译。

但事实是,这是糟糕的设计!您应该以这样的方式设计您的 classes,以便您可以真正对重要功能进行单元测试,并且您可以做功能测试。您可以使用模拟等。提前设计。我刚才展示的 - 我们用来测试一些旧代码,人们在其中编写代码 - UI 逻辑、BLL 逻辑和数据访问逻辑都在同一个文件中。没办法,你应该这样写一个新的代码

使您的代码难以测试的主要问题是这种方法做的太多了。

你想测试什么?在最简单的情况下,您需要测试基本的 happy path,用户在其中输入正确的密码(稍后会详细介绍)并输出正确的帐户详细信息。您还需要测试 'unhappy path' 用户输入不正确的密码,并显示一条错误消息而不是用户的帐户详细信息。

更复杂的是,在您的代码上下文中,Console.WriteLine 是第 3 方依赖项,尽管来自信誉良好的来源。在单元测试中,我们的目标是隔离 unit of work. What this means is that you don't want to be calling the real Console.WriteLine in the method that you're unit testing. However, because Console.WriteLine is a static method it's difficult to mock,这是隔离工作单元通常采用的方法。当然,您仍然希望确保将写入屏幕的详细信息符合预期。有多种方法,但最简单的可能是 将构造用户输出的代码与实际显示它的代码分开

这里的另一个问题是此方法依赖于 Program class(myIdmyPassmyName 等字段中的状态)。在单元测试中,您需要控制传递给这些变量的值,如果它们是 Program class 中的静态成员,则无法执行此操作。作为初学者,您可以将这些传递到您的 showInfo() 方法中,从而允许您控制传递给单元测试的内容。

总结:要使此代码可单元测试,您需要将其分解为更小的组件,您可以单独对其进行单元测试。

进一步注意:您的 .Contains 用户 ID 和密码测试看起来很可疑,如果两个人使用相同的密码会怎样?

编辑 下面是一个示例,说明您可以如何着手将此方法分解为更小的方法,这些方法可以单独进行单元测试。请注意,此代码仍然可以进行改进,但我故意将其保留为与 OP 中的代码非常相似,因此更容易在两者之间进行比较:

public class Class1
{
    public void showInfo(
        string[] myId,
        string[] myPass,
        string[] myName,
        string[] myAccType,
        string[] myDob,
        string[] myDomain,
        string[] myManager)
    {
        int indexNum;
        string inId = Convert.ToString(Console.ReadLine());//taking Id as input 
        Console.Write("Enter account Password :");
        string inPass = Convert.ToString(Console.ReadLine());//taking password

        if (IsPasswordValid(inId, inPass, myId, myPass))
        {
            var successOutputLines = GetSuccessOutput(
                inId,
                myId,
                myPass,
                myName,
                myAccType,
                myDob,
                myDomain,
                myManager);
            successOutputLines.ToList().ForEach(l => Console.WriteLine(l));
        }
        else
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Login Error!", Console.ForegroundColor);
            Console.ResetColor();
        }
    }

    public bool IsPasswordValid(
        string userId,
        string passwordIn,
        string[] userIds,
        string[] passwords)
    {
        var userIndex = Array.IndexOf(userIds, userId);
        if (userIndex == -1)
            throw new ArgumentException(nameof(userId));
        var expectedPassword = passwords[userIndex];
        return expectedPassword == passwordIn;
    }

    public IEnumerable<string> GetSuccessOutput(
        string userId,
        string[] myId,
        string[] myPass,
        string[] myName,
        string[] myAccType,
        string[] myDob,
        string[] myDomain,
        string[] myManager)
    {
        var userIndex = Array.IndexOf(myId, userId);
        if (userIndex == -1)
            throw new ArgumentException(nameof(userId));

        var lines = new List<string>();
        lines.Add("Login Success!");
        lines.Add("Your details: ");
        lines.Add("Your details: ");
        lines.Add("Name: " + myName[userIndex]);
        lines.Add("Id: " + myId[userIndex]);
        lines.Add("Acc Type: " + myAccType[userIndex]);
        lines.Add("Date of Joining: " + myDob[userIndex]);
        lines.Add("Domain: " + myDomain[userIndex]);
        lines.Add("Manager: " + myManager[userIndex]);

        return lines;
    }
}

然后您将为 IsPasswordValidGetSuccessOutput 方法编写单元测试。