如何测试/更改未经测试和不可测试的代码?

aby*_*byx 9 legacy refactoring unit-testing

最近我不得不在旧系统上更改一些代码,而不是所有代码都有单元测试.
在进行更改之前,我想编写测试,但是每个类都创建了许多依赖项和其他反模式,这使得测试变得非常困难.
显然,我想重构代码,以便更容易测试,编写测试然后更改它.
这是你的方式吗?或者您是否会花费大量时间编写难以编写的测试,这些测试在重构完成后将被删除?

Mik*_*one 6

首先,这是一篇很棒的文章,内容涉及单元测试.其次,我找到了一种避免在旧代码中进行大量更改的好方法,只需稍微重构一下就可以测试它.一种简单的方法是使私有成员受到保护,然后覆盖受保护的字段.

例如,假设您有一个类在构造函数期间从数据库加载一些东西.在这种情况下,您不能仅覆盖受保护的方法,但可以将DB逻辑提取到受保护的字段,然后在测试中覆盖它.

public class MyClass {
    public MyClass() {
        // undesirable DB logic
    }
}
Run Code Online (Sandbox Code Playgroud)

public class MyClass {
    public MyClass() {
        loadFromDB();
    }

    protected void loadFromDB() {
        // undesirable DB logic
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你的测试看起来像这样:

public class MyClassTest {
    public void testSomething() {
        MyClass myClass = new MyClassWrapper();
        // test it
    }

    private static class MyClassWrapper extends MyClass {
        @Override
        protected void loadFromDB() {
            // some mock logic
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个不好的例子,因为你可以在这种情况下使用DBUnit,但我最近在类似的情况下做了这个,因为我想测试一些与正在加载的数据完全无关的功能,所以它非常有效.我也发现这样的暴露成员在其他类似的情况下是有用的,我需要摆脱长时间在类中的一些依赖.

如果您正在编写框架,我建议不要使用此解决方案,除非您真的不介意将成员暴露给框架的用户.

这有点像黑客,但我发现它非常有用.