1

我想在下面的方法上运行一些单元测试,我将一个模拟接口(vehicleObject)传递给ProcessVehicles,但是一旦它被传递,它就会被确定车辆类型重新分配,所以我的模拟对象没有用。我的第一个想法是创建一个布尔值来确定是否 应该运行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。从长远来看,也许完全重构是答案,在这一点上,这不是我正在寻找的答案,也许没有其他选择。

方法确定车辆类型是私有的

注意:我知道有代码异味,这是当前有效的遗留代码。我想围绕它进行测试而不是改变它,所以它看起来很漂亮,然后在生产中中断。完全重构可能是我只想确保模拟工具没有其他解决方案的唯一选择。

4

2 回答 2

3

有什么访问修饰符DetermineVehicleType?您可以将该方法存根,以便它返回您的模拟接口(我相信 Roy Osherove 将此称为abstract test driver pattern)。否则,这看起来像是重构的主要候选者:)

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

首先,更改您的方法签名

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

然后,在您的测试中,您可以从上述类中创建一个存根,并让它返回您的存根 IObject,无论CarObject传入的是什么。您可以通过从该类继承来手动创建一个存根类,也可以使用类似的东西MOQ 来实现这一点。让我知道您是否需要我再详细说明一下。

然而,另一个注意事项:

重构它的更好方法是简单地IObject将 但是,也许这只是来自这个简化的例子ProcessVehiclesProcessVehicles

全面实施更新

    [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
    {
    }
于 2012-03-21T19:26:01.103 回答
1

如果我们非常直截了当,我相信您的代码会散发出异味。

考虑一下:该方法ProcessVehicles调用实例上的一个方法,称为DetermineVehicleType. 你的班级是做什么的?是这样Process Vehicles,还是这样Determine Vehicle Type?如果你从字面上理解,这对我来说表明违反了 SRP。你的班级正试图做不止一项工作。

Arguably this implies that SRP disapproves of private helper methods. Some commentators do indeed hold this to be the case. I'm not sure I do; as always, common sense is key.

If I were to refactor this code, I would give the class something like an IVehicleCategoryHelper which exposes DetermineVehicleType. Perhaps this would be passed in through its constructor, or if we are implementing full-on Fat Dependency Injection, an IFactory so that the instance can retrieve an IVehicleCategoryHelper when it needs one, dependent on context.

Take everything I've said with a pinch of salt. I don't necessarily believe that this is the right approach - it will ultimately be up to you to decide.

于 2012-03-21T19:57:03.653 回答