关于单元测试:设计套接字创建测试,TDD Java

Designing a test for socket creation, TDD Java

我开始使用一些测试驱动的开发实践,我在决定是否以及如何测试我的代码时遇到问题。

我有一个包含ServerSocketFactoryServerSocket的类AbstractServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class AbstractServer extends Thread {

    ...SNIP...
    //ServerSocket and factory.
    private ServerSocket ss;
    private ServerSocketFactory ssf;

    public AbstractServer ( int _port ) {
        this.port = _port;

        try {
            ssf = ServerSocketFactory.getDefault();
            ss = ssf.createServerSocket(port);
        } catch (IOException e) {
            // Couldn't create ServerSocket, die.
            System.exit(1);
        }
    }
    ... SNIP ...

ServerSocketServerSocketFactory都是private,并且永远不会暴露在此类之外。

我的问题:

  • 我应该创建测试来检查我是否真的创建ServerSocketServerSocketFactory? 它们private并且没有从课堂上暴露出来 - 测试过多的测试?

  • 如果测试他们的创建是我应该做的,我如何从类外部测试私有的,非暴露的(没有getter方法)对象创建? 我的天真(读:未经测试)假设是我创建了一个测试类extending AbstractServer; 然后,我必须制作我正在测试protected的东西,这半就失败了让它们private开始的目的。


  • 首先,在单元测试期间不要考虑类的内部细节。对于您的单元测试,正在测试的类是一个黑盒子。您没有关于其内部结构的信息。这就是单元测试的想法。

    现在,问问自己一个问题:你的课程所面临的功能是什么?根据您的示例,它创建一个服务器套接字并开始监听它。现在使用单元测试作为指定此功能的方法(伪代码):

    1
    2
    3
    int port = 12345;
    AbstractServer server = new AbstractServer(port) { };
    new Socket("localhost", port);

    而已。该测试解释了您的课程如何运作以及它的作用。当/如果类停止提供该功能时 - 测试将失败并指示您。这正是测试的目的。


  • 我不编写用于填充类变量的单元测试,这太简单了,在我看来,不需要测试。我编写单元测试来测试例程。例如,要确保我的add()方法实际添加并且我的remove()方法实际上删除了(正确的对象)。如果这些类变量出于某种原因而没有正确实例化,那么我的功能测试就会抓住这个。
  • 至于测试private变量/类,我建议看看以下答案:https://stackoverflow.com/a/7075965/1201423。它背后的基本概念是:如果它是private而你需要测试它,它真的应该是private吗?

  • 首先测试抽象类不是一个好主意。您应该测试具体的实现。抽象类只是一种删除代码重复的方法(通过IS-A关系),你可以通过许多其他方式删除重复(例如我喜欢的是HAS-A关系)。

    查看您的代码和您的问题可能是您的好视频:
    如何编写干净,可测试的代码。
    它会告诉你为什么你采取的方法可能不是一个好主意,并会指出一些示例解决方案。

    通常:指定您提供的场景/功能。不要测试实现细节。

    初学者的良好知识来源是:测试驱动开发博客。看看那里的旧帖子。

    编辑:
    如果您想测试遗留代码,那么还有一些模式。在这种情况下,一般规则是从接受开始,而不是单元测试。


    您并不需要专门测试这个简单的构造函数。只有两个调用 - 这两个调用都是可公开访问的方法,可以进行测试以确保它们能够自行运行。即使在更复杂的构造函数情况下,也应该使用可测试的构建器模式。

    至于多少太多,我有时可能最终放松一点封装以使测试更容易,但这实际上取决于情况。通常,只要您彻底测试公共API,您就可以确信模块中的所有代码都正常工作 - 如果公共API完全正常工作,那么任何私有代码都应该没有问题。

    这里有一些关于tdd的文章,在一些更难以涵盖的领域:这里