将 TestSettings 参数注入到方法以使其(单元或集成)可测试是一个好主意吗?
引入 TestSettings 类以便为内部具有多个进程的方法提供灵活的测试可能性是一个好习惯吗?
也许不是一个很好的例子,但可以很简单:假设我有这个方法,并且我想测试它的子流程:
public void TheBigMethod(myMethodParameters parameter)
{
if(parameter.Condition1)
{
MethodForCondition1("BigMac");
}
if(parameter.Condition2)
{
MethodForCondition2("MilkShake");
}
if(parameter.Condition3)
{
MethodForCondition3("Coke");
}
SomeCommonMethod1('A');
SomeCommonMethod2('B');
SomeCommonMethod3('C');
}
并想象我对所有
- void MethodForCondition1 (string s)
- void MethodForCondition2 (string s)
- void MethodForCondition3 ( string s)
- void SomeCommonMethod1 (char c)
- void SomeCommonMethod2 (char c)
- void SomeCommonMethod3 (char c)
现在我想通过引入带有所需断言的测试方法来测试 TheBigMethod 本身:
- TheBigMethod_MethodForCondition1_TestCaseX_DoesGood
- TheBigMethod_MethodForCondition2_TestCaseY_DoesGood
- TheBigMethod_MethodForCondition3_TestCaseZ_DoesGood
- TheBigMethod_SomeCommon Method1_TestCaseU_DoesGood
- TheBigMethod_SomeCommonMethod2_TestCaseP_DoesGood
- TheBigMethod_SomeCommonMethod3_TestCaseQ_DoesGood
所以,我如果 TheBigMethod 被我上面的集成测试之一调用,则希望它在某些时候可退出。
public void TheBigMethod(myMethodParameters parameter, TestSettings setting)
{
if(parameter.Condition1)
{
MethodForCondition1("BigMac");
if(setting.ExitAfter_MethodForCondition1)
return;
}
if(parameter.Condition2)
{
MethodForCondition2("MilkShake");
if(setting.ExitAfter_MethodForCondition2)
return;
}
if(parameter.Condition3)
{
MethodForCondition3("Coke");
if(setting.ExitAfter_MethodForCondition3)
return;
}
SomeCommonMethod1('A');
if(setting.ExitAfter_SomeCommonMethod1)
return;
SomeCommonMethod2('B');
if(setting.ExitAfter_SomeCommonMethod2)
return;
SomeCommonMethod3('C');
if(setting.ExitAfter_SomeCommonMethod3)
return;
}
尽管它看起来确实满足了我的需要,但引入 TestSetting 参数可能会降低代码的可读性,并且将测试逻辑和主要功能结合起来看起来不太好。
您能否针对这种情况提出更好的设计建议,以便它可以取代 TestSetting 参数的想法?
谢谢
Is it a good practice to introduce a TestSettings class in order to provide flexible testing possibilities of a method that has many processes inside?
Maybe not a good example but can be simple: Suppose that I have this method and I want to test its sub-processes:
public void TheBigMethod(myMethodParameters parameter)
{
if(parameter.Condition1)
{
MethodForCondition1("BigMac");
}
if(parameter.Condition2)
{
MethodForCondition2("MilkShake");
}
if(parameter.Condition3)
{
MethodForCondition3("Coke");
}
SomeCommonMethod1('A');
SomeCommonMethod2('B');
SomeCommonMethod3('C');
}
And imagine that I have unit tests for all
- void MethodForCondition1 (string s)
- void MethodForCondition2 (string s)
- void MethodForCondition3 (string s)
- void SomeCommonMethod1 (char c)
- void SomeCommonMethod2 (char c)
- void SomeCommonMethod3 (char c)
And now i want to test the TheBigMethod itself by introducing such test methods with required Asserts in them:
- TheBigMethod_MethodForCondition1_TestCaseX_DoesGood
- TheBigMethod_MethodForCondition2_TestCaseY_DoesGood
- TheBigMethod_MethodForCondition3_TestCaseZ_DoesGood
- TheBigMethod_SomeCommonMethod1_TestCaseU_DoesGood
- TheBigMethod_SomeCommonMethod2_TestCaseP_DoesGood
- TheBigMethod_SomeCommonMethod3_TestCaseQ_DoesGood
So, I want TheBigMethod to be exit-able at some points if it is called by one of my integration tests above.
public void TheBigMethod(myMethodParameters parameter, TestSettings setting)
{
if(parameter.Condition1)
{
MethodForCondition1("BigMac");
if(setting.ExitAfter_MethodForCondition1)
return;
}
if(parameter.Condition2)
{
MethodForCondition2("MilkShake");
if(setting.ExitAfter_MethodForCondition2)
return;
}
if(parameter.Condition3)
{
MethodForCondition3("Coke");
if(setting.ExitAfter_MethodForCondition3)
return;
}
SomeCommonMethod1('A');
if(setting.ExitAfter_SomeCommonMethod1)
return;
SomeCommonMethod2('B');
if(setting.ExitAfter_SomeCommonMethod2)
return;
SomeCommonMethod3('C');
if(setting.ExitAfter_SomeCommonMethod3)
return;
}
Even though it looks it does what I need to introduce a TestSetting parameter can makee the code less readable and does not look nice to have testing logic and the main functionality combined to me.
Can you advise a better design for such cases so that it can replace a TestSetting parameter idea?
thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
添加此测试设置(IMO)是一件非常糟糕的事情。另一种方法是为 MethodForConditionX 和 SomeCommonMethodX 添加一个接口(或一组接口)。测试每个 MethodForConditionX & SomeCommonMethodX 独立存在,并传入 TheBigMethod 的存根,该存根验证使用值 Z 调用 MethodForConditionX。
编辑:您还可以将如果您不想使用接口,则可以使用虚拟方法。
It would (IMO) be a very bad thing to add this TestSetting. An alternative would be to add an interface (or set of interfaces) for MethodForConditionX and SomeCommonMethodX. The test each of the MethodForConditionX & SomeCommonMethodX in isolation and pass in a stub for TheBigMethod which validates that MethodForConditionX is called with value Z.
Edit: You could also make the methods virtual if you don't want to use an interface.
这里的游戏有点晚了,但我同意混合测试和生产代码是需要避免的大代码味道。遗留代码中的大方法会带来各种各样的问题。我强烈建议您阅读 Michael Feather 的有效地使用旧代码。这一切都是关于处理遗留代码中遇到的无数问题以及如何处理它们。
A bit late to the game here, but I would concur that mixing test and production code is a big code smell to be avoided. Big methods in legacy code provide all sorts of issues. I would highly recommend reading Michael Feather's Working Effectively with Legacy Code. It's all about dealing with the myriad of problems encountered in legacy code and how to deal with them.