如何对创建新对象的类进行单元测试

时间:2012-10-05 16:15:37

标签: java unit-testing junit mockito

我正在使用JUnit和Mockito来测试一些类。该类本身从另一个类创建一个对象。一个名为testList的列表。这是我的代码:

public class A {
       private List<B> bList;

       //returns the bList
       public List<B> getBList() {
          return bList;
       }

       //checks the status by calling getStatus in class B
       public Status getStatus() {
          //status is an enum consists of PASSED and FAILED
          Status finalStatus = Status.PASSED;
          for (B be : this.getTestList()) {
             if (be.getStatus() != Status.PASSED) {
                finalStatus = Status.FAILED;
                break;
             }
          }
          return status;
       }
    }


    public Class B {
       private Status status = Status.FAILED;   

       public getStatus() {
          return status;
       }

       public void setStatus(Status status) {
          this.status = status;
       }
    }

在名为Test的类中测试getStatus和getTestList方法的最佳方法是什么。

非常感谢....

3 个答案:

答案 0 :(得分:4)

我看了你的ClassA,我想知道bList是如何设置的。{1}}现在,除了null之外没有办法使它成为任何东西,这意味着getStatus每次都会抛出一个空指针异常。

您的问题是您正在考虑如何测试方法,而不是考虑如何测试行为。这是一个问题的一个原因是您的类必须以某种方式适应您的应用程序的其余部分。为了确保它能够做到这一点,它需要某些行为,而不是每种方法中的某些细节。所以唯一有意义的测试就是检查行为。

或许更加阴险的是,测试单个方法会让您专注于您实际编写 的代码。如果您在编写测试时查看代码,那么您的测试将成为一个自我实现的预言。您可能错过了您的班级需要提供的一整套行为;但是如果你只测试你的班级提供提供的行为,那么你永远不会知道。

所以,回到手头的问题。我看到你的班级可能会实现四种,也许五种行为。也许还有更多 - 很难说你是否只向我们展示了代码,而不是规范。你应该为每一个写一个测试。我坚信每个测试的名称应该描述行为,而不是反映测试使用的方法的名称。在这种情况下,我可能会选择这样的名字。

public void statusIsPassedWhenEveryTestPassed()
public void statusIsFailedWhenEveryTestFailed()
public void statusIsFailedWhenSomeTestsPassedSomeFailed()
public void statusIsPassedWhenNoTests()
public void statusIsPassedWhenTestsNotSet() // this one currently fails

在每个测试中,我将创建一个ClassA的对象,然后执行必要的操作以在对象中设置bList。最后,我会调用getStatus并声明返回值是我想要的。但重要的是,每个测试(除了最后一个测试)使用多个ClassA方法,因此这些不是单个方法的测试。

答案 1 :(得分:0)

您可以为相关对象提供setter(或构造函数注入)作为protected,然后在测试用例中扩展类以模拟对象,或者您可以尝试使用powermock之类的东西。您仍然需要提供一种方法来设置有问题的对象。

答案 2 :(得分:0)

我想这取决于你如何在单元测试中填充testList。如果你有一个setter,那么你就不需要任何模拟框架

class TestTest {

  Test test = new Test();

  @Test void should_return_failed_if_a_single_test_failed() {
     givenTestListWithOneFailedTest();
     assertThat(test.getStatus(), is(Status.FAILED))
  }

  void givenTestListWithOneFailedTest() {
     test.setTestList(createSomeTestListWithOnlyOneFailedTest());
  }

  @Test void should_return_passed_if_all_tests_passed() {
     // ...
  }

}