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

C# 为这个表达式计算器类的私有方法编写单元测试可以吗?,c#,unit-testing,expression,C#,Unit Testing,Expression,我有以下代码 public interface IInterpreter { decimal Evaluate(string expression); } public class Interpreter : IInterpreter { public decimal Evaluate(string expression) { if (String.IsNullOrWhiteSpace(expression)) throw new


我有以下代码

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”等表达式
现在我想写单元测试。这里唯一的公共功能是
评估
,根据所有建议,只有该方法应进行测试
问题是我强烈地感觉到,
ConvertToReversePolishNotation(expression)
EvaluateReversePolishExpression(rpnExpression)
函数都必须包含在单元测试中。。。如果某个单元测试因
Evaluate
方法而失败,它将不会指出错误的位置(在
convertorpnexpression
方法或
EvaluateReversePolishExpression
函数中)。

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

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


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

是的,可以。

您正在进行单元测试
Evaluate
,它将完成
ConvertToReversePolishNotation
EvaluateReversePolishExpression
的实际实现

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);
}

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

而不是使用构造函数依赖项注入来与实际实现解耦。 您可以手动实例化它,也可以委托容器来初始化它,这样您就可以在不改变解释器的情况下更改行为

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

您可以单独测试单个类的每个实现

您的类也遵循单一责任原则,因为它负责验证并调用外部类来执行操作,所以它负责描述事件流


此外,如果您将实现类紧密地结合起来进行转换和评估,那么您就违反了开-关原则。

@您可以使用“单一责任原则”来验证类是否过于复杂。通常,单元测试问题是一个很好的指标,验证只是一个简单的保护。为什么要将input guard移动到一个单独的类?据我所知,你同意@Aphelion,但你的简短回答是肯定的,而他的答案是否定的:)@我很失望,我同意你可以将它分开,我不同意他的
No
不为私有函数编写单元测试是不好的。这基本上是你大胆的问题。有时候,忽视是不可避免的。仅仅因为其中一本书/作者说为私有函数编写单元测试不好并不意味着这是一条硬规则。好吧,他的问题是在这种情况下的
,而不是一条硬规则:)