2

私のプロジェクトはテスト駆動開発を開始したいので、プロジェクト用に Junit 4 (現在は Eclipse Juno を使用した JUnit 4.10) に関する小さなチュートリアルを書くことにしました。

Bill.java

import java.util.ArrayList;
import java.util.List;

/**
 * @author funkymonkey
 * 
 *         Class Bill can store an id and a priceList (List<Float>)
 *         - id with setter and getter
 *         - prices can be added to the priceList
 *         - getter for priceList
 *         - total amount of price in priceList can be calculated
 */

public class Bill {
   private Integer     id;       // invoice number (one for every Bill)

   private List<Float> priceList; // list will contain prices of the products

   public Bill() {
      priceList = new ArrayList<Float>();
   }

   public Bill(Integer id) {
      this.id = id;

      priceList = new ArrayList<Float>();
   }

   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   public List<Float> getPriceList() {
      return priceList;
   }

   public void addPrice(Float price) {
      if (price <= 0) {
         throw new IllegalArgumentException("Value is less or equal zero");
      }

      priceList.add(price);
   }

   public float getTotalPrice() {
      float totalPrice = 0;

      for (Float p : priceList) {
         totalPrice = totalPrice + p;
      }
      return totalPrice;
   }
}

BillTest.java

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.matchers.JUnitMatchers.hasItems;

import java.util.ArrayList;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class BillTest {

   private static Bill       jBill1;
   private static final float FLOAT_1        = (float) 1;
   private static final float FLOAT_20       = (float) 20;
   private static final float FLOAT_3P345    = (float) 3.345;
   private static final float FLOAT_0P000001 = (float) 0.000001;

   @Before
   // initialize objects before running tests
   public void setUp() throws Exception {
      jBill1 = new Bill();
   }

   @After
   // something which should be done after running a single test
   public void tearDown() throws Exception {
   }

   @Test
   // test addPrice()
   public final void testAddPrice_priceIsGreaterThanZero() {
      jBill1.addPrice(FLOAT_1);
      jBill1.addPrice(FLOAT_20);
      jBill1.addPrice(FLOAT_3P345);
      jBill1.addPrice(FLOAT_0P000001);

      // check if expected values == results

      // we are comparing lists so we are using assertEquals(expected, result)
      List<Float> expectedList = new ArrayList<Float>();
      expectedList.add(FLOAT_1);
      expectedList.add(FLOAT_20);
      expectedList.add(FLOAT_3P345);
      expectedList.add(FLOAT_0P000001);
      List<Float> resultList = jBill1.getPriceList();

      assertEquals(expectedList, resultList);

      // we are comparing arrays so we can use assertArrayEquals(expected, result)
      Object[] expectedArray = { FLOAT_1, FLOAT_20, FLOAT_3P345, FLOAT_0P000001 };
      Object[] resultArray = jBill1.getPriceList().toArray();

      assertArrayEquals(expectedArray, resultArray);

      // we are comparing strings to we can use assertEquals(expected, result)
      String expectedString = expectedList.toString();
      String resultString = jBill1.getPriceList().toString();

      assertEquals(expectedString, resultString);

      // let us compare the size of the lists using assertTrue (boolean condition)
      Integer expectedLength = expectedList.size();
      Integer resultLength = jBill1.getPriceList().size();

      assertTrue(expectedLength == resultLength);
      // or use assertTrue(expectedLength.equals(resultLength));

      // you can also use your own matchers by using assertThat(result, matcher)
      assertThat(resultList, hasItems(expectedList.toArray(new Float[expectedList.size()])));
      // or assertThat(resultList, hasItems(FLOAT_1, FLOAT_20, FLOAT_3P345, (float)
      // 0.000001));

   }

   @Test(expected = IllegalArgumentException.class)
   // test will pass if exception is thrown from addPrice()
   public final void testAddPrice_priceIsZero() {
      // this will throw the exception IllegalArgumentException
      jBill1.addPrice((float) 0);
   }

   @Test(expected = IllegalArgumentException.class)
   // test will pass if exception is thrown from addPrice()
   public final void testAddPrice_priceIsLessThanZero() {
      // this will throw the exception IllegalArgumentException
      jBill1.addPrice((float) -1);
   }

   @Test
   // test if calculating works via getTotalPrice()
   public final void testGetTotalPrice() {
      jBill1.addPrice(FLOAT_1);
      jBill1.addPrice(FLOAT_20);
      jBill1.addPrice(FLOAT_3P345);
      jBill1.addPrice(FLOAT_0P000001);

      Float expectedValue = FLOAT_1 + FLOAT_20 + FLOAT_3P345 + FLOAT_0P000001;
      Float resultValue = jBill1.getTotalPrice();

      // we are comparing float values so we can use assertEquals(expected, result)
      assertEquals(expectedValue, resultValue);
   }
}

私の質問は次のとおりです。

  • 昔ながらのコーダー (ウォーターフォール モデル) に JUnit からどのように利益を得ることができるかを説明する方法
  • 役立つ可能性のある追加のパッケージ (モックフレームワーク?)
  • JUnit で最も重要なメソッドは?
  • サンプル コードは、junit の機能を誰かに説明するのに役立ちますか?
4

1 に答える 1

0

一般的に: ハードコードされた魔法の数字は使用しないでください。定数をより適切に定義して、1 つのポイントで編集できるようにします。

 public static final float FLOAT_1  =  1;
 public static final float FLOAT_20 = 20;

 public final void testAddPrice_priceIsGreaterThanZero() {
   expectedList.add((float) FLOAT_1);
   expectedList.add((float) FLOAT_20);
   List<Float> expectedList = new ArrayList<Float>();
   expectedList.add((float) FLOAT_1);
   expectedList.add((float) FLOAT_20);
   //...
 }

JUnit のような単体テストは、「1 つの責任に対して 1 つのテスト」として設計されています。したがって、メソッド#getPriceList()などgetPriceList().toString()について、すべての分離されたテストを定義します(すべてsetUp()のテストは他のテストとは無関係に実行する必要があるため、追加を行うことができます)。JUnit はフェイルファストです。つまり、最初に失敗したテストの後に、テスト メソッドをビークします。したがって、最初に失敗したテストの後にすべてのテストが失われます。

テストメソッドにJavaDocを追加して、機能をテストする方法を説明できます。ランダムなサンプル値、予想される例外など

于 2012-10-09T14:09:35.633 に答える