我有下面的代码
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函数中)。
所以问题是-在本例中可以为私有函数编写单元测试吗?
发布于 2016-08-22 13:12:54
不是的。
将ConvertToReversePolishNotation方法重构为单独的类。它关心的是转变。
翻译关心的是评估。如果您“模拟”转换的输出,那么使用公共Evaluate方法应该很容易进行测试。
发布于 2016-08-22 13:24:24
我会创建三个类,一个负责验证,一个负责转换,另一个负责评估。
而不是使用构造函数依赖项注入来与实际实现分离。您可以手动实例化它,也可以委托容器来启动它,您将能够更改行为而不需要修改解释器。
如果您沿着这条路线走下去,您可以很容易地测试依赖项的调用顺序,因此您将测试解释器的行为。比如验证,转换,评估。
单独测试单个类的每个实现。
您的类也是刹车单责任原则,因为是负责验证和调用外部类执行一个操作,所以负责描述一个事件流。
此外,如果将转换和评估的实现类紧密耦合在一起,则会破坏Open原则。
发布于 2016-08-22 13:24:04
是的,没事的,。
您是单元测试Evaluate,它通过ConvertToReversePolishNotation和EvaluateReversePolishExpression的实际实现。
Aphelion是正确的,您可以根据自己的责任将类分开,但是只有对于ConvertToReversePolishNotation,如果您这样做,甚至不需要为EvaluateReversePolishExpression创建一个私有方法,因为这已经是它正在做的事情了(目前)。调用之前,调用方应该调用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);
}https://stackoverflow.com/questions/39080488
复制相似问题