我想对下面的方法运行一些单元测试我将一个模拟的接口( vehicleObject )传递给 ProcessVehicles 但是一旦传递它就会被重新分配通过 DetermineVehicleType ,所以我的模拟对象是没用的。我的第一个想法是创建一个布尔值来确定是否应该运行 DetermineVehicleType 并将其添加为参数,但这听起来非常混乱。有没有更好的方法来解决这个问题?
注入Mock对象的方法:
public void ProcessVehicles(ICarObject CarObject)
{
IObject vehicleObject = DetermineVehicleType(carObject);
vehicleObject.ProcessVehicle(carObject);
}
原始代码:
public void ProcessVehicles()
{
IObject vehicleObject = DetermineVehicleType(carObject);
vehicleObject.ProcessVehicle(carObject);
}
注意:在调用 DetermineVehicleType 之前,我无法检查vehicleObject是否为null,因为在实际使用该类时它可能不为null。从长远来看,也许总重构是答案,在这一点上,这不是我正在寻找的答案,也许没有其他选择。
方法DetermineVehicleType是私有的
注意:我知道有代码味道这是当前有效的遗留代码。我想围绕它进行测试而不是改变它,所以它看起来很漂亮,然后在生产中中断。总重构可能是我唯一想要确保没有使用模拟工具的解决方案的唯一选择。
答案 0 :(得分:3)
DetermineVehicleType
有哪些访问修饰符?您可以存根该方法,以便它返回您的模拟接口(Roy Osherove称之为abstract test driver pattern
,我相信)。否则,这看起来像重构的主要候选人:)
要重构您的代码,您可以执行类似这样的操作
首先,更改您的方法签名
protected virtual IObject DetermineVehicleType(CarObject obj)
{
//Do whatever you normally do
}
然后,在您的测试中,您可以从上面的类创建一个存根,并让它返回您的存根IObject,无论传入CarObject
。您可以通过继承来自手动创建一个存根类。类,或者你可以使用像MOQ这样的东西来完成这个。如果您需要我再详细说明一下,请告诉我。
然而,另一个注意事项是:
更好的重构方法是简单地将IObject
传递给ProcessVehicles
,因为从这个示例中可以看出这里有SRP违规行为,其中{ {1}}方法不仅仅是处理它们。但是,也许这只是来自这个简化的例子
完整实施更新
ProcessVehicles
答案 1 :(得分:1)
如果我们非常直白,我相信你的代码会显示出一种气味。
请考虑这一点:方法ProcessVehicles
在名为DetermineVehicleType
的实例上调用方法。你的班级做什么?是Process Vehicles
还是Determine Vehicle Type
?这对我来说表明违反SRP,如果你从字面上理解它。你的班级正在努力做一份以上的工作。
可以说这意味着SRP不赞成私人助手方法。一些评论员确实认为这是事实。我不确定我这样做;一如既往,常识是关键。
如果我要重构这段代码,我会给类似IVehicleCategoryHelper
的内容,它会公开DetermineVehicleType
。也许这将通过它的构造函数传递,或者如果我们实现全面的Fat Dependency Injection,一个IFactory,以便实例可以在需要时检索IVehicleCategoryHelper,这取决于上下文。
用一小撮盐把我所说的一切都拿走。我不一定相信这是正确的方法 - 最终由您决定。