2

因为我的项目想要开始测试驱动开发,所以我决定为我的项目编写一个关于 Junit 4(目前是带有 Eclipse Juno 的 JUnit 4.10)的小教程。

比尔.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

一般来说:不要使用魔法硬编码数字。更好地定义常量,以便您可以在一个点编辑它们:

 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 这样的单元测试被设计为“一项职责的一项测试”。因此,对于您的方法#getPriceList()等,getPriceList().toString()定义所有单独的测试(可以添加,setUp()因为每个测试都应该独立于其他测试运行)。JUnit 是快速失败的,这意味着在第一次失败的测试之后,它将破坏测试方法。因此,如果您在一个测试方法中接受它们,那么您在第一次失败的测试后会丢失所有测试。

您可以将 JavaDoc 添加到您的测试方法中,以描述它们如何测试功能。随机示例值、预期异常等

于 2012-10-09T14:09:35.633 回答