是否可以为此Expression求值程序类的私有方法编写单元测试?

时间:2016-08-22 13:10:34

标签: 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 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函数中)。

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

3 个答案:

答案 0 :(得分:5)

没有

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

口译员的关注点是评估。如果你'嘲笑'转换的输出应该很容易使用公共Evaluate方法进行测试。

答案 1 :(得分:2)

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

比使用构造函数依赖注入从实际实现中解耦。 无论是手动实例化还是委托Container启动它,您都可以更改行为而无需更改解释器。

如果沿着这条路线前进,您可以轻松测试依赖项的调用顺序,因此您将测试Interpreter的行为。 比如,验证,转换,评估。

除了可以测试单个类的每个实现之外。

你的班级也制定单一责任原则,因为负责验证并且还要调用外部类确实执行操作,所以负责描述事件流。

此外,如果您将转换和评估的实现类紧密结合在一起,那么您就违反了Open Close原则。

答案 2 :(得分:1)

是的,没关系。

您正在进行单元测试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);
}