C# 有没有更好的方法来测试这个方法?

C# 有没有更好的方法来测试这个方法?,c#,unit-testing,nunit,justmock,C#,Unit Testing,Nunit,Justmock,我想对下面的方法运行一些单元测试,我正在将模拟接口(vehicleObject)传递到ProcessVehicles中,但一旦传递,它就会被DetermineHicleType重新分配,因此我的模拟对象没有任何用处。我的第一个想法是创建一个布尔值来确定是否应该运行DeterminateHicleType并将其添加为参数,但这听起来非常混乱。有没有更好的办法解决这个问题 正在注入模拟对象的方法: public void ProcessVehicles(ICarObject CarObject) {

我想对下面的方法运行一些单元测试,我正在将模拟接口(vehicleObject)传递到ProcessVehicles中,但一旦传递,它就会被DetermineHicleType重新分配,因此我的模拟对象没有任何用处。我的第一个想法是创建一个布尔值来确定是否应该运行DeterminateHicleType并将其添加为参数,但这听起来非常混乱。有没有更好的办法解决这个问题

正在注入模拟对象的方法:

public void ProcessVehicles(ICarObject CarObject)
{
    IObject vehicleObject = DetermineVehicleType(carObject);
    vehicleObject.ProcessVehicle(carObject);
}
原始代码:

public void ProcessVehicles()
{
    IObject vehicleObject = DetermineVehicleType(carObject);
    vehicleObject.ProcessVehicle(carObject);
}
注意:在调用DeterminateHicleType之前,我无法检查vehicleObject是否为null,因为在实际使用该类时,它可能不是null。从长远来看,也许完全重构是答案,在这一点上,这不是我想要的答案,也许没有其他选择

DetermineHicleType方法是私有的


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

什么访问修饰符是
确定hicletype
的?您可以删除该方法,使其返回模拟接口(我相信Roy Osherove将其称为
抽象测试驱动程序模式
)。否则,这看起来像是重构的主要候选对象:)

要重构代码,您可以执行以下操作

首先,更改您的方法签名

protected virtual IObject DetermineVehicleType(CarObject obj)
{
    //Do whatever you normally do
}
然后,在测试中,您可以从上述类中创建一个存根,并让它返回存根IOObject,而不管传入的是
CarObject
。您可以通过从该类继承来手动创建存根类,也可以使用类似MOQ的方法来实现这一点。如果你需要我再详细解释一下,请告诉我

然而,另一项说明是:

更好的重构方法是将
IObject
传递给
ProcessVehicles
,因为从本例中可以看出,这里有一个冲突,
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
    {
    }
[测试]
公共void TestMethod()
{
var testerStub=新的testerStub();
testerStub.ProcessVehicles();
//在这里断言某事
}
公共类测试员桶:测试员
{
公共覆盖IObject determinateHicleType(CarObject obj)
{
var mockObject=new Mock();
Setup(x=>x.SomeMethod).Returns(Something);
返回mockObject.Object;
}
}
公共类测试员
{
受保护的虚拟IOObject DeterminateHicleType(CarObject obj)
{
返回新的ObjectTester();
}
公共交通工具()
{
var carType=determinatevehicletype(new CarObject());
}
}
公共类ObjectTester:IOObject
{
}
公共接口对象
{
}
公共类CarObject
{
}

什么访问修饰符决定了hicletype
的访问修饰符?您可以删除该方法,使其返回模拟接口(我相信Roy Osherove将其称为
抽象测试驱动程序模式
)。否则,这看起来像是重构的主要候选对象:)

要重构代码,您可以执行以下操作

首先,更改您的方法签名

protected virtual IObject DetermineVehicleType(CarObject obj)
{
    //Do whatever you normally do
}
然后,在测试中,您可以从上述类中创建一个存根,并让它返回存根IOObject,而不管传入的是
CarObject
。您可以通过从该类继承来手动创建存根类,也可以使用类似MOQ的方法来实现这一点。如果你需要我再详细解释一下,请告诉我

然而,另一项说明是:

更好的重构方法是将
IObject
传递给
ProcessVehicles
,因为从本例中可以看出,这里有一个冲突,
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
    {
    }
[测试]
公共void TestMethod()
{
var testerStub=新的testerStub();
testerStub.ProcessVehicles();
//在这里断言某事
}
公共类测试员桶:测试员
{
公共覆盖IObject determinateHicleType(CarObject obj)
{
var mockObject=new Mock();
Setup(x=>x.SomeMethod).Returns(Something);
返回mockObject.Object;
}
}
公共类测试员
{
受保护的虚拟IOObject DeterminateHicleType(CarObject obj)
{
返回新的ObjectTester();
}
公共交通工具()
{
var carType=determinatevehicletype(new CarObject());
}
}
公共类ObjectTester:IOObject
{
}
公共接口对象
{
}
公共类CarObject
{
}

如果我们非常直白,我相信您的代码会显示出一种气味

考虑一下:方法
ProcessVehicles
调用名为
DeterminateHicleType
的实例上的方法。你们班做什么?它是
处理车辆
,还是
确定车辆类型
?这对我来说意味着违反了SRP,如果你从字面上理解的话。你们班正在尝试做不止一项工作

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

如果我要重构这段代码,我会给这个类一个类似于
IVehicleCategoryHelper的东西,它公开<