单元测试私有字段

时间:2016-06-23 08:22:55

标签: java unit-testing junit tdd

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

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中的noob,我能做的就是 - 为someList编写一个公共getter和setter,并在单元测试中使用它们。但它在概念上是错误的 - 我不希望类的客户端使用此成员变量directlty。

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

6 个答案:

答案 0 :(得分:5)

You are getting unit testing wrong.

Unit testing is about testing behavior of your classes; not implementation details.

You don't test if private fields do have this or that content. The only thing you test is that methods do what they are supposed to do.

That of course means that your class must have ways to insert "special lists" for testing.

Long story short: you want to step back, and spent the next 2, 3 hours learning how to write "easy to test code"; for example by watching the great videos from Google Tech on CleanCode

答案 1 :(得分:1)

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

private List<Object> someList;

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

使用此模拟列表测试您的方法。您还可以使用@BeforeClass来模拟列表。您可以阅读@Before和@BeforeClass here

之间的差异

答案 2 :(得分:0)

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

另一种选择是在Groovy中编写测试,可以直接访问Java类中的私有字段。因此,您无需访问您的私人字段。

答案 3 :(得分:0)

您可以像这样测试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);
    }

答案 4 :(得分:0)

如果您在测试目录中使用与您的类包相同的名称创建一个包,并且如果您将该字段置于受保护状态,则您将能够直接访问该字段

答案 5 :(得分:0)

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

看看你想测试什么,然后努力。您没有在标准中提到列表本身很重要。重要的是您查询数据库的次数。