单元测试中如何处理private方法和变量

642 阅读1分钟

在Java类中private方法和成员变量通常只能在当前类中被调用,其他类一般无法触及。单元测试private方法似乎是件困难的事情。为了解决,有些人会尝试将private改为public,或是将测试方法写进private方法的所属类中。但这样就违背了单元测试的AIR原则:

  • A:Automatic(自动化)
  • I:Independent(独立性)
  • R:Repeatable(可重复)

单元测试执行时,应该感觉像空气(AIR)那样透明。

在单元测试中如何处理private方法&变量

我们可以用Java的反射特性来突破private的限制,从而对private方法进行单元测试:

测试目标类:

public class DemoService {
    private String demoString;
    private String printString() {
        demoString = "changed by printString()";
        return "private method is invoked.";
    }
}

单元测试代码:

import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.*;

class DemoServiceTest {
    @Test
    void callPrivateMethod() throws Exception{
        DemoService demoService = new DemoService();

        // 通过反射调用private方法
        Method methodPrintString = demoService.getClass().getDeclaredMethod("printString");
        methodPrintString.setAccessible(true);
        assertEquals("private method is invoked.", methodPrintString.invoke(demoService));
        
        // 通过反射访问private变量
        Field fieldDemoString = demoService.getClass().getDeclaredField("demoString");
        fieldDemoString.setAccessible(true);
        assertEquals("changed by printString()", fieldDemoString.get(demoService));
    }
}

要不要对private方法写单元测试?

网上对这个问题有很多的讨论,详情见我们仍没有对私有方法是否需要进行测试达成共识

个人的观点,单元测试的主要目的是把bug暴露在软件开发的构建期,不应该强行遵守规范因噎废食。通常对不重要的private方法可以不做单元测试。但对重要的方法还是有做单测的必要的。

我是BloodyPanda,专注SRE和Java后端开发,欢迎关注我。