繁体   English   中英

单元测试私有字段

[英]Unit testing private fields

我有一个简单的类,其中包含一个列表:

public class SomeClass {

    private AppDataSource appDataSource; // it's interface
    private List<Object> someList;

    ////

    public List<Obejct> loadSomeList() {
        if (someList == null) {
            return appDataSource.getListFromDatabase();
        }
        retrunf someList;
    }
}

关键是-我希​​望该列表仅从DB加载一次。 我想对该功能进行单元测试。 我在TDD中是菜鸟,我能做的就是-为someList编写一个公共的getter和setter方法,并在单元测试中使用它们。 但这在概念上是错误的-我不希望类的客户端直接使用此成员变量。

在这种情况下如何正确测试方法?

您正在错误进行单元测试。

单元测试是关于测试类的行为 没有实施细节。

您不测试私有字段是否具有此内容。 您测试的唯一一件事是方法执行了应做的事情。

当然,这意味着您的班级必须具有插入“特殊列表”进行测试的方法。

长话短说:您想退后一步,并花了接下来的2、3个小时来学习如何编写“易于测试的代码”; 例如,通过CleanCode观看Google Tech的精彩视频。

您应该在测试之前模拟列表。使用@Before初始化列表。

private List<Object> someList;

@Before 
 public void initialize() {
    someList = new ArrayList<Object>();
    someLisi.add(..);
    someList.add(..);
 }

并使用此模拟列表测试您的方法。您还可以使用@BeforeClass模拟列表。 您可以在此处阅读@Before和@BeforeClass之间的区别

您可以通过测试夹具中的构造函数来初始化私有字段。 我猜这是最普通的方式。

另一个选择是用Groovy编写测试,该测试可以直接访问Java类中的私有字段。 因此,您无需授予对私有字段的访问权限。

您可以像这样测试您的loadSomeList()

public class SomeClass {

    private List<Object> someList;

    public List<Object> loadSomeList() {
        if (someList == null) {
            someList = new ArrayList<>();
            someList.add(new Object());
            return someList;
        }
        return someList;
    }

    public List<Object> getSomeList() {
        return someList;
    }

    public void setSomeList(List<Object> someList) {
        this.someList = someList;
    }

测试类应该有两个测试:

  • 在第一个测试中,您可以测试是否有新的列表。 您创建一个SomeClass的新实例,并调用someClass.loadSomeList()方法。 如果列表不为空,则表示测试通过。
  • 第二项测试可以测试someClass实例是否已经具有列表。 在测试中,您只需在列表中添加一个对象并将其设置为someClass

public class SomeClassTest {

    @Test
    public void testLoadSomeListNewList() {
        SomeClass someClass = new SomeClass();
        List<Object> list = someClass.loadSomeList();
        assertNotNull(list);
    }

    @Test
    public void testLoadSomeListGivenList() {
        SomeClass someClass = new SomeClass();
        List<Object> list = new ArrayList<>();
        list.add(new Object());
        someClass.setSomeList(list);

        someClass.loadSomeList();
        assertTrue(someClass.getSomeList().size() == 1);
    }

如果您在测试目录中创建的包与该类的包的名称相同,并且将该字段置于受保护的位置,则可以直接访问该字段

无需公开和测试列表,而是更改appDataSource以便可以从类外部进行设置。 使它成为提供getListFromDatabase()方法的接口。 然后进行测试,传入一个实现接口的模拟数据源,该数据源具有一个计数器,您可以查询该计数器以告知您调用了getListFromDatabase方法的次数。

查看您要测试的内容,然后再进行测试。 您没有在标准中提到列表本身很重要。 重要的是查询数据库的次数。

暂无
暂无

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

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