可以为这个表达式计算器类的私有方法编写单元测试吗

本文关键字:有方法 单元测试 计算器 表达式 | 更新日期: 2023-09-27 18:03:22


我有以下代码

public interface IInterpreter
{
    decimal Evaluate(string expression);
}
public class Interpreter : IInterpreter
{
    public decimal Evaluate(string expression)
    {
        if (String.IsNullOrWhiteSpace(expression))
            throw new ArgumentException("Parameter " + nameof(expression) + " cannot be empty");
        var rpnExpression = ConvertToReversePolishNotation(expression);
        return EvaluateReversePolishExpression(rpnExpression);
    }
...
 }

此类将计算"5+5*6"或"(3-5(*(2+2(+5"等表达式
现在我想写单元测试。这里唯一的公共函数是Evaluate,根据所有建议,只应对该方法进行测试
问题是,我有一种强烈的感觉,ConvertToReversePolishNotation(expression)EvaluateReversePolishExpression(rpnExpression)函数都必须用单元测试来覆盖。。。如果Evaluate方法的某些单元测试失败,它不会指出错误在哪里(在ConvertToRPNExpression方法或EvaluateReversePolishExpression函数中(。

所以问题是-在这种情况下,为私有函数编写单元测试可以吗

可以为这个表达式计算器类的私有方法编写单元测试吗

否。

ConvertToReversePolishNotation方法重构为一个单独的类。它关心的是转换。

口译员关心的是评估。如果"模拟"转换的输出,那么使用公共Evaluate方法应该很容易进行测试。

我将创建三个类,一个负责验证,一个用于转换,另一个用于评估。

然后使用构造函数依赖项注入与实际实现解耦。无论是手动实例化它,还是委托Container来启动它,都可以在不需要更改解释器的情况下更改行为。

如果您走这条路,您可以很容易地测试依赖项的调用顺序,因此您将测试解释器的行为。类似,验证,转换,评估。

您可以分别测试单个类的每个实现。

您的类也在制动单一责任原则,因为它负责验证和调用外部类执行操作,所以负责描述事件流。

此外,如果您将Conversion和Evaluation的实现类紧密地耦合在一起,那么您就违反了"打开-关闭"原则。

是的,没关系

您正在对Evaluate进行单元测试,它将贯穿ConvertToReversePolishNotationEvaluateReversePolishExpression的实际实现。

Aphelion是正确的,你可以根据自己的责任来分离类,但只有对于ConvertToReversePolishNotation,如果你这样做的话,你甚至不需要为EvaluateReversePolishExpression创建一个私有方法,因为这已经是它(目前(正在做的了。在调用evaluate之前,调用者应该调用ConvertToReversePolishNotation的类,并将其作为参数传入。

如果您还担心不进行private方法的单元测试,那么您可以使用internal方法。

脱离主题:您还必须记住如何扩展和扩展此功能。如果您的解释器也想返回除decimal之外的数据类型,会发生什么情况?难道你不想最大化仿制药吗?

public decimal Evaluate(string expression)
{
    if (String.IsNullOrWhiteSpace(expression))
        throw new ArgumentException("Parameter " + nameof(expression) + " cannot be empty");
    return EvaluateReversePolishExpression(expression);
}