简体   繁体   English

有没有更好的方法来测试这种方法?

[英]is there a better way to test this method?

I would like to run some unit tests on the method below I am passing a mocked interface( vehicleObject ) into ProcessVehicles but as soon as it is passed it gets reassigned by DetermineVehicleType so my mocked object is of no use. 我想对下面的方法运行一些单元测试我将一个模拟的接口( vehicleObject )传递给ProcessVehicles但是一旦传递它就会被DetermineVehicleType重新分配,所以我的模拟对象是没用的。 My first idea would be to create a boolean to determine if DetermineVehicleType should be run and add it as a param, but that sounds so very messy. 我的第一个想法是创建一个布尔值来确定是否应该运行DetermineVehicleType并将其添加为参数,但这听起来非常混乱。 Is there a better way to get around this ? 有没有更好的方法解决这个问题?

Method with Mock object being injected: 注入Mock对象的方法:

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

Original Code: 原始代码:

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

Note: I can't check if vehicleObject is null before calling DetermineVehicleType because it might not be null when the class is actually used. 注意:在调用DetermineVehicleType之前,我无法检查vehicleObject是否为null,因为在实际使用该类时它可能不为null。 In the long run maybe total refactor is the answer, at this point that is not the answer I am looking for maybe there is not another option. 从长远来看,也许总重构是答案,在这一点上,这不是我正在寻找的答案,也许没有其他选择。

the method DetermineVehicleType is private 方法DetermineVehicleType是私有的

Note: I know there are code smells this is legacy code that currently works. 注意:我知道有代码味道这是当前有效的遗留代码。 I want to get tests around it not change it so it looks pretty and then breaks in production. 我想围绕它进行测试而不是改变它,所以它看起来很漂亮,然后在生产中中断。 Total refactor might be the only option I just want to make sure there is not another solution with the mock tools. 总重构可能是我唯一想要确保没有使用模拟工具的解决方案的唯一选择。

What access modifier does DetermineVehicleType have? DetermineVehicleType有哪些访问修饰符? You could stub out that method so that it returns your mocked interface (Roy Osherove calls this the abstract test driver pattern , I believe). 您可以存根该方法,以便它返回您的模拟接口(Roy Osherove称之为abstract test driver pattern ,我相信)。 Otherwise, this looks like a prime candidate for refactoring :) 否则,这看起来像重构的主要候选人:)

To refactor your code you would do something like this 要重构你的代码,你会做这样的事情

First, change your method signature 首先,更改方法签名

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

Then, in your test, you can create a stub out of the above class, and have it return your stubbed IObject no matter the CarObject passed in. You can either manually create a stub class by inheriting from the class, or you could use something like MOQ to accomplish this. 然后,在您的测试中,您可以从上面的类创建一个存根,并让它返回您的存根IObject,无论CarObject传入。您可以通过继承该类手动创建存根类,或者您可以使用某些东西喜欢MOQ来实现这一目标。 Let me know if you need me to elaborate on this a little more. 如果您需要我再详细说明一下,请告诉我。

Another note, however: 但另一个注意事项是:

A better way to refactor this would be to simply pass in the IObject to the ProcessVehicles , as it seems from this example that you have a SRP violation here, where the ProcessVehicles method is doing more than processing them. 重构这个的更好方法是简单地将IObject传递给ProcessVehicles ,因为从这个例子看,你在这里有一个SRP违规,其中ProcessVehicles方法所做的不仅仅是处理它们。 But, maybe that is just from this simplified example 但是,也许这只是来自这个简化的例子

FULL Implementation Update 完整的实施更新

    [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
    {
    }

If we are being very literal, I believe your code demonstrates a smell. 如果我们非常文字,我相信你的代码会显示出一种气味。

Consider this: the method ProcessVehicles calls a method on the instance called DetermineVehicleType . 考虑一下:方法ProcessVehicles在名为DetermineVehicleType的实例上调用方法。 What does your class do? 你的班级做什么? Does it Process Vehicles , or does it Determine Vehicle Type ? 它是Process Vehicles ,还是Determine Vehicle Type This to me indicates violation of SRP, if you take it literally. 这对我来说表明违反SRP,如果你从字面上理解它。 Your class is trying to do more than one job. 你的班级正在尝试做多个工作。

Arguably this implies that SRP disapproves of private helper methods. 可以说这意味着SRP不赞成私人助手方法。 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 . 如果我要重构这个代码,我会给类类似于IVehicleCategoryHelper的类,它暴露了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. 也许这将通过它的构造函数传递,或者如果我们实现全面的Fat Dependency Injection,一个IFactory,以便实例可以在需要时检索IVehicleCategoryHelper,这取决于上下文。

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. 我不一定认为这是正确的方法 - 最终由您来决定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM