简体   繁体   English

如何重构遗留代码以更好地适合单元测试

[英]How to refactor legacy code to be better suited for unit tests

I have this legacy code I inherited.我继承了这个遗留代码。 The problem is I have this read-only class that handles some parsing logic.问题是我有这个处理某些解析逻辑的只读类。

public class ParsedClass
{
    public int ID 
    { 
       get { return _id; }
    }
    private readonly int _id;

    public bool IsMale
    { 
       get { return _isMale; }
    }
    private readonly bool _isMale;

    public ParsedClass(byte[] payload)
    {
        // parsing logic
        // assign properties etc etc 
    }
}

This code then gets passed to some business logic that depends on this parsed class.然后,此代码将传递给依赖于此已解析类的某些业务逻辑。 And is used something like.并使用类似的东西。

public class BusinessLogic
{
    public int ProcessingLogic(ParsedClass obj)
    {
        // do some processing stuff 
        User acct = DataAccess.GetUser(obj.ID);
        if(obj.IsMale)
            // do some other business logic 
    }
}

So as you can see the class is tightly coupled with the business logic.因此,正如您所见,该类与业务逻辑紧密耦合。 Since the parsing class is closed from the outside.由于解析类是从外部关闭的。 The only way to unit test some functions is to create a payload that has the data I need.对某些功能进行单元测试的唯一方法是创建一个包含我需要的数据的有效负载。 How could I best refactor this to make it more open for unit testing?我怎样才能最好地重构它以使其对单元测试更开放?

Initially, I thought about opening up the class to modification from the outside.最初,我考虑过开放课程以从外部进行修改。 This would let me assign the values I need without having to craft a specific payload for each scenario.这将让我分配我需要的值,而不必为每个场景制作特定的有效载荷。 But, I have been reading around stack, and it seems like doing this would be bad design.但是,我一直在阅读堆栈,这样做似乎是糟糕的设计。

Consider adding protected or internal constructor to your ParsedClass :考虑向您的ParsedClass添加protectedinternal构造函数:

public class ParsedClass
{
    // your legacy stuff

    protected ParsedClass(int id, bool isMale)
    {
        _id = id;
        _isMale = isMale;
    }
}

Then you can add opened inherited class for tests ( with internal constructor of the base class you needn't this, but your tests must be in the same assembly however ):然后你可以为测试添加打开的继承类(使用基类的internal构造函数你不需要这个,但是你的测试必须在同一个程序集中):

public class TestParsedClass : ParsedClass
{
    public TestParsedClass(int id, bool isMale) : base(id, isMale)
    {
    }
}

Now you can test your BusinessLogic class from wherever:现在您可以从任何地方测试您的BusinessLogic类:

new BusinessLogic().ProcessingLogic(new TestParsedClass(5, true));

Another way is to declare interface for your ParsedClass :另一种方法是为您的ParsedClass声明interface

public interface IParsedClass
{
    public int ID { get; }

    public bool IsMale { get; }
}

Then refactor your classes like this:然后像这样重构你的类:

public class ParsedClass : IParsedClass
{
    // your legacy stuff
}

public class BusinessLogic
{
    public int ProcessingLogic(IParsedClass obj)
    {
        // your legacy stuff
    }
}

Now you can create some test class implementing IParsedClass like this:现在您可以像这样创建一些实现IParsedClass的测试类:

public class TestParsedClass : IParsedClass
{
    public int ID { get; set; }

    public bool IsMale { get; set; }
}

and use it in your BusinessLogic unit tests.并在您的BusinessLogic单元测试中使用它。

This approach gives you bonus advantage - your ProcessingLogic method become more flexible now.这种方法为您带来额外优势 - 您的ProcessingLogic方法现在变得更加灵活。


Hope this would be suitable for your project.希望这适合您的项目。

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

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