为 if else 语句编写单元测试

Posted

技术标签:

【中文标题】为 if else 语句编写单元测试【英文标题】:Writing a unit test for an if else statement 【发布时间】:2021-06-07 05:52:37 【问题描述】:

我是单元测试新手,对 c# 也很陌生,非常感谢有关如何编写单元测试以确保 AddGrade 方法中的逻辑正常工作的一些帮助。所以基本上如果等级是 >=0 并且

我看过另一篇关于在 c# 中对 if-else 语句进行单元测试的帖子,并尝试从中解决这个问题,但老实说它让我感到困惑。我已经在网上四处查看,并尝试了很多不同的方法来尝试解决这个问题,但有时我发现很难将人们的示例应用到我的代码中,所以我认为最好只是发布我的代码并获得一些帮助,任何帮助都会不胜感激:)

我正在使用 Xunit 进行单元测试。该项目在控制台中运行。

这是带有main方法的程序类

    using System;
using System.Collections.Generic;

namespace GradeBook

    class Program
    
        static void Main(string[] args)
        
            var book = new Book("Dave's");

            //add grade to the book
            book.AddGrade(90.5);
            book.AddGrade(80.5);
            book.AddGrade(70.5);
            book.AddGrade(60.5);

            var stats = book.GetStatistics();
            Console.WriteLine($"This Gradebooks name is book.Name");
            Console.WriteLine($"The highest grade is stats.High:N1");
            Console.WriteLine($"The lowest grade is stats.Low:N1");
            Console.WriteLine($"The average grade is stats.Average:N1");//N1,N2 etc. is number of decimal places
        
    

这是我要为其编写单元测试的 AddGrade 方法所在的书类

    using System;
using System.Collections.Generic;

namespace GradeBook

    public class Book
    
        public Book(string name)
        
            grades = new List<double>();
            Name = name;
        

        public void AddGrade(double grade)
        
            if (grade >= 0 && grade <= 100)
            
                grades.Add(grade);               
            
            else
            
                Console.WriteLine("Please enter a value between 0 and 100");
            
        

        public Statistics GetStatistics()
        
            var result = new Statistics();
            result.Average = 0.0;
            result.High = double.MinValue;
            result.Low = double.MaxValue;
            

            foreach (var grade in grades)
            
                Console.WriteLine($"Name grade is: grade");
                result.Low = Math.Min(grade, result.Low);
                result.High = Math.Max(grade, result.High);
                result.Average += grade;
                
                
            
            result.Average /= grades.Count;
            return result;           
        

        private List<double> grades = new List<double>()  ;
        public string Name;
    

这是统计类

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GradeBook

    public class Statistics
    
        public double Average;
        public double High;
        public double Low;
    

这是我为此编写单元测试的地方

    using System;
    using System.Collections.Generic;
    using Xunit;
    
    namespace GradeBook.Tests
    
        public class BookTests
        
            [Fact]
            public void BookGradeIsValid()
            
                var book = new Book("");           
                book.AddGrade(105);
            
        
    

【问题讨论】:

欢迎来到单元测试的精彩世界!列表“等级”在哪里定义?它是否在 BookTests 范围内公开访问? 当你的代码很难测试时,很可能是因为它不是为了便于测试而编写的。在这里,我认为您对控制台的硬依赖是一个问题。你不能轻易地模拟控制台。因此,要么尝试通过返回指示成功与否的结果来完成代码中的控制台。改为抛出异常或使用具有可以模拟和干净测试的接口的不同类封装 Console。 【参考方案1】:

我建议你修改你的 AddGrade() 方法以在添加无效成绩时抛出异常:

public void AddGrade(double grade)
        
            if (grade >= 0 && grade <= 100)
            
                grades.Add(grade);               
            
            else
            
                throw new ArgumentException("grade must be between 0 and 100");
            
        

你可以这样测试:

[Fact]
public void BookGradeIsValid()

      var book = new Book("");           
      Assert.Throws<ArgumentExeception>(() => book.AddGrade(101)); // should throw
      Assert.Throws<ArgumentExeception>(() => book.AddGrade(-1)); // should throw
      book.AddGrade(0); // should not throw
      book.AddGrade(100); // should not throw

作为提示,不要使用 105 进行测试。直接在边界处使用值。如果您有错字并且写了 if (grade &gt;= 0 &amp;&amp; grade &lt;= 103) 而不是 100,那么您在测试中不会意识到这一点。

使用异常有几个优点。首先,您也可以在非控制台应用程序中使用 Book 类。其次,如果出现问题,您可以进行自定义错误处理:

int grade = 300;
try

book.AddGrade(grade)

catch(ArgumentException)

   // so many possibilities: log to console or display a MessageBox or
   // send an e-mail to system admin or add grade with a default value or ...

此外,您不能忽略异常。如果你添加了一个无效值的成绩,你的程序将停在那里,你不会想知道代码后面的 200 行,为什么缺少一个成绩。

【讨论】:

我可以建议使用ArgumentOutOfRangeException吗?另一个建议是使用 proper names 或至少使用一组参数 (InlineDataAttribute?) 将测试拆分为多个,因为单个测试应该执行单个 acting 感谢您的建议,它确实很有帮助,我理解为什么这也有效,以及为什么使用边界值也是一个好主意。

以上是关于为 if else 语句编写单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何在角度 9 中为多个 if else 语句编写测试用例

如何使用 Angular 4 Jasmine 单元测试用例覆盖 IF/ELSE 条件

多行var声明上的Jest单元测试分支覆盖率

编写单元测试用例说明书的依据是啥

python中单元测试的常用语句

使用 Jest 对 V-If 进行单元测试