首页 > 解决方案 > 单元测试可以使用被测类的方法进行测试设置吗

问题描述

我有一个有 6 个方法的类 Inventory。我应该在一个名为 InventoryTEST 的测试类中为这 6 个方法中的每一个实现测试。类对象是一个哈希图。

这是该类的方法

 /**
   * Return the number of Records.
   */
  public int size() { }

  /**
   * Return a copy of the record for a given Video.
   */
  public Record get(VideoObj v) {  }

  /**
   * Return a copy of the records as a collection.
   * Neither the underlying collection, nor the actual records are returned.
   */
  public Collection toCollection() {}

  /**
   * Add or remove copies of a video from the inventory.
   * If a video record is not already present (and change is
   * positive), a record is created. 
   * If a record is already present, <code>numOwned</code> is
   * modified using <code>change</code>.
   * If <code>change</code> brings the number of copies to be less
   * than one, the record is removed from the inventory.
   * @param video the video to be added.
   * @param change the number of copies to add (or remove if negative).
   * @throws IllegalArgumentException if video null or change is zero
   * @postcondition changes the record for the video
   */
  public void addNumOwned(VideoObj video, int change) {

  }

  /**
   * Check out a video.
   * @param video the video to be checked out.
   * @throws IllegalArgumentException if video has no record or numOut
   * equals numOwned.
   * @postcondition changes the record for the video
   */
  public void checkOut(VideoObj video) {
  }

  /**
   * Check in a video.
   * @param video the video to be checked in.
   * @throws IllegalArgumentException if video has no record or numOut
   * non-positive.
   * @postcondition changes the record for the video
   */
  public void checkIn(VideoObj video) {

  }

  /**
   * Remove all records from the inventory.
   * @postcondition <code>size() == 0</code>
   */
  public void clear() {

  }

现在为了测试这些方法,我需要创建一个包含一些记录的对象。我可以做到这一点的一种方法是调用默认构造函数,它将给我一个空的哈希图,然后调用 addNumOwned 将记录添加到哈希图中。我可以做到这一点的另一种方法是创建一个重载的构造函数,它可以在创建时在哈希图中添加记录。

我在第一种方法中看到的问题是 addNumOwned 是在测试类中测试的方法(和单元)。因此,如果这个单元出现故障,所有其他单元也会出现故障。一个单元测试是否应该怀疑另一个单元测试的失败?

我想如果我必须对构造函数进行单元测试,同样的参数也会成立。但是,我没有对构造函数进行单元测试。

标签: javaunit-testingjunit

解决方案


如果您正在为一个类编写一套测试,那么您的一些测试的设置代码可以使用该类的方法。事实上,避免这样做几乎是不可能的。

如果您希望您的测试全面,您将需要测试您的类的构造函数。但是当然,作为设置阶段的一部分,您类的方法的所有测试都必须首先创建您的类的对象。

public ThingTest // We have a class named Thing we want to test, this is its unit tests
{

   @Test
   public void testIncrement() // Test of the Thing.increment method
   {
      // Set up:
      var thing = new Thing(); // Using part of the Thing class in the set up phase!

      // Exercise:
      thing.increment();

      // Verify:
      assertEquals(1, thing.count());
   }
...

我猜您很担心,因为您希望安排您的测试,以便您正在测试的代码中的错误仅导致一次测试失败,因此调试测试失败很容易。那是一个理想,值得为之奋斗,但也只是一个理想。在实践中,某些类型的错误和测试不可能这么简单。

您可以通过确保进行全面的测试以及自下而上的测试来缓解这一困难。也就是说,如果测试的设置阶段依赖于正确运行的特定 mutator 或构造函数,则您必须对该 mutator 或构造函数进行单元测试。

对于复杂的代码,您可以考虑使用 Java 级别assert的语句(我的偏好)或JUnit 假设来检查测试的设置阶段是否已正确完成,然后再执行您正在测试的方法。然后,您将不会遇到难以调试的测试失败,而是会AssertionErrorAssumptionViolatedException清楚TestAbortedException地指出问题的原因。

   @Test
   public void testIncrement()
   {
      var thing = new Thing();
      assert thing.count() == 0;

      thing.increment();

      // Verify:
      assertEquals(1, thing.count());
   }
...

推荐阅读