2012-03-21 150 views
1

我想在方法运行一些单元测试,下面我传递一个嘲笑接口(vehicleObject)到ProcessVehicles但只要它是通过由DetermineVehicleType它被重新分配,所以我的嘲笑对象是无使用。我的第一个想法是创建一个布尔值,以确定是否应该运行DetermineVehicleType并将其添加为参数,但听起来非常混乱。有没有更好的方法来解决这个问题?有没有更好的方法来测试这种方法?

与模仿对象方法注入:

public void ProcessVehicles(ICarObject CarObject) 
{ 
    IObject vehicleObject = DetermineVehicleType(carObject); 
    vehicleObject.ProcessVehicle(carObject); 
} 

原始代码:

public void ProcessVehicles() 
{ 
    IObject vehicleObject = DetermineVehicleType(carObject); 
    vehicleObject.ProcessVehicle(carObject); 
} 

注:我无法检查vehicleObject调用DetermineVehicleType,因为它可能不是空之前是空当班级被实际使用时。从长远来看,也许总重构是答案,在这一点上,这不是我正在寻找的答案,也许没有其他选择。

方法DetermineVehicleType是私人

注:我知道有代码异味,这是遗留代码,目前的工作。我想得到它的测试不会改变它,所以它看起来很漂亮,然后停止生产。总重构可能是我唯一想确定模拟工具没有另一个解决方案的唯一选择。

+0

如果你模拟vehicleObject,你想测试什么?如果ProcessVehicle被调用或什么的? – 2012-03-21 19:27:18

+0

您能否详细解释ProcessVehicles方法的目标是什么?我觉得这里的代码味道不好。通过将一个对象传递给一个函数并用一个以carObject作为参数的函数改变它的引用。 – daryal 2012-03-21 19:28:02

+0

@WouterdeKort我想获得测试方法ProcessVehicles – 2012-03-21 19:28:49

回答

3

什么访问修饰符DetermineVehicleType有?你可以把这个方法剔除,以便它返回你的模拟界面(Roy Osherove称之为abstract test driver pattern,我相信)。否则,这看起来像一个总理候选人重构:)

重构你的代码,你会做这样的事情

首先,改变你的方法签名

protected virtual IObject DetermineVehicleType(CarObject obj) 
{ 
    //Do whatever you normally do 
} 

然后,在您的测试,你可以在上面的类中创建一个存根,并且无论传入的是CarObject,它都会返回您的存根IObject。您可以通过继承类来手动创建存根类,也可以使用MOQ之类的方法来完成此操作。让我知道你是否需要我详细说明这一点。

另要注意,但是:

一种更好的方式重构,这将是简单地在IObject传递给ProcessVehicles,因为它从这个例子,你在这里有一个SRP违规行为,其中ProcessVehicles方法似乎不仅仅是处理它们。不过,这也许就是刚刚从这个简单的例子

全面实施更新

[Test] 
    public void TestMethod() 
    { 
     var testerStub = new TesterStub(); 
     testerStub.ProcessVehicles(); 
     //Assert something here 
    } 

    public class TesterStub : Tester 
    { 
     public override IObject DetermineVehicleType(CarObject obj) 
     { 
      var mockObject = new Mock<IObject>(); 
      mockObject.Setup(x => x.SomeMethod).Returns(Something); 
      return mockObject.Object; 
     } 
    } 

    public class Tester 
    { 
     protected virtual IObject DetermineVehicleType(CarObject obj) 
     { 
      return new ObjectTester(); 
     } 

     public void ProcessVehicles() 
     { 
      var carType = DetermineVehicleType(new CarObject()); 

     } 
    } 

    public class ObjectTester : IObject 
    { 
    } 

    public interface IObject 
    { 
    } 

    public class CarObject 
    { 
    } 
+0

答案更新...有关如何重构的任何想法? – 2012-03-21 19:27:27

+1

更新后再解释一点。 – 2012-03-21 19:38:49

+0

是的,我同意在我重构项目之前,有很多违规行为是我想要获得项目的。你能详细阐述一下你的重构想法吗? – 2012-03-21 19:42:06

1

如果我们是非常字面,相信你的代码演示了气味。

请考虑:方法ProcessVehicles在名为DetermineVehicleType的实例上调用方法。你的班级做什么?请问Process Vehicles,还是Determine Vehicle Type?这对我来说表示违反了SRP,如果你从字面上理解。你的班正在努力做不止一份工作。

可以说这意味着SRP不赞成私人帮手方法。有些评论员确实认为这是事实。我不确定我是否确定;一如既往,常识是关键。

如果我要重构这段代码,我会给这个班级做个类似IVehicleCategoryHelper的公开DetermineVehicleType。也许这将通过它的构造函数传递,或者如果我们正在实现完全开发的Fat依赖注入,则需要一个IFactory,以便实例可以在需要时根据上下文检索IVehicleCategoryHelper。

把一切我说过的一撮盐。我不一定相信这是正确的方法 - 它最终取决于你自己决定。

+0

已编辑的问题 – 2012-03-21 20:00:51

相关问题