【发布时间】:2017-06-04 13:39:03
【问题描述】:
以下是我的产品代码本质和简化表示。 这就像一个完成工作流程的算法。每个步骤(私有方法)都会导致数据库中的记录发生更改。甚至外部工具调用也会导致通过另一种回调反馈机制更新数据库。
void IWorkFlow.PerformBusinessWorkflowX(Input input)
{
PreparePreRequisiteData();
DoTask_A();
TriggerExternalToolTo_DoTask_B(); /* external tool invocation */
}
我的一位同事想为此编写一个集成测试用例,但不想包含外部工具调用。如果 BusinessWorkFlow 逻辑处于集成级别但不包括外部工具,他的目标是测试其余部分。不是使用模拟的单元测试,而是集成测试,他在其中验证数据库前后测试的状态。为了达到目的,他这样修改了代码。
void IWorkFlow.PerformBusinessWorkflowX(Input input, bool isTriggerExternalTool)
{
PreparePreRequisiteData();
DoTask_A();
if(isTriggerExternalTool)
{
TriggerExternalToolTo_DoTask_B(); /* external tool invocation */
}
}
但是,我对这种重构风格并不满意。由于外部工具的调用是业务工作流程中不可分割/不可分割的一部分,因此我宁愿不将产品代码修改为具有指示工具调用是可选的布尔标志。
我认为更好的解决方案(但丑陋(?)因为它的性质)是坚持使用原始方法而不需要传入布尔标志依赖项。相反,决定调用该工具来支持测试嵌入到 TriggerExternalToolTo_DoTask_B() 方法中。甚至可以调用它 TryTriggerExternalToolTo_DoTask_B()。
类似的,
private void TryTriggerExternalToolTo_DoTask_B()
{
//will be false for integration tests. Any other value then invoke.
if(ConfigurationManager.AppSettings["InvokeTool"] != "false")
{
}
}
不知何故,我也不赞成将 IWorkFlow.PerformBusinessWorkflowX(Input input) 方法分解为两部分(一部分执行前 2 个步骤,第二部分仅执行通过不同接口方法公开的工具调用),只是为了为了产品代码的灵活性和支持测试代码。也因为所有步骤都属于单个工作流(算法)。
问题
1) 我是否说错了在产品代码中引入布尔标志只是为了支持测试可能不是最佳实践? (有些人告诉我,这就是可测试性设计。我希望这不是可测试性设计的真正含义)
2) 将调用逻辑下推到 TryTriggerExternalToolTo_DoTask_B() 并依靠 appsetting 来救援的看似丑陋的解决方案是更好的解决方案吗?
3)看到我不想为了灵活而分解方法(扩展接口),有没有更好的解决上述问题的方法?
PS - 如果我不了解,请纠正我,并提供开放的技术建议。
【问题讨论】:
-
根据您在这里所说的,改变设计是我认为的“最佳”解决方案。我没有发现 1 或 2 比另一个特别好。他们只是在不同的方面很糟糕。至于“可测试性设计”,不,我当然不会认为 1 是一个例子。
标签: .net coding-style refactoring api-design testability