码迷,mamicode.com
首页 > 其他好文 > 详细

JUnit单元测试

时间:2016-06-21 07:12:44      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:

概述

JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立

github地址

https://github.com/junit-team/junit4

Junit官网

http://junit.org/junit4

注:主要是翻译,但是并没有翻译全文。

入门

这个小例子展示了如何写一个单元测试。你需要安装jdk,有文本编辑器。

准备

创建一个jnnit-example文件夹,下载并引入junit的jar包,所有的文件都在那个文件夹下创建,命令也是在那执行。
创建Caculator.java文件
public class Calculator {
  public int evaluate(String expression) {
    int sum = 0;
    for (String summand: expression.split("\\+"))
      sum += Integer.valueOf(summand);
    return sum;
  }
}
编译文件
javac Calculator.java
编译之后会生成Calculator.class文件

创建单元测试

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class CalculatorTest {
  @Test
  public void evaluatesExpression() {
    Calculator calculator = new Calculator();
    int sum = calculator.evaluate("1+2+3");
    assertEquals(6, sum);
  }
}
在linux或者mac上编译
javac -cp .:junit-4.XX.jar CalculatorTest.java
在windows上编译
javac -cp .;junit-4.XX.jar CalculatorTest.java
执行单元测试
在linux或者mac平台上
java -cp .:junit-4.XX.jar:hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorTest
在winddows平台上
java -cp .;junit-4.XX.jar;hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorTest

输出

JUnit version 4.12
.
Time: 0,006

OK (1 test)
这是执行成功的输出结果。
如果执行错误,错误的输出样例
JUnit version 4.12
.E
Time: 0,007
There was 1 failure:
1) evaluatesExpression(CalculatorTest)
java.lang.AssertionError: expected:<6> but was:<-6>
  at org.junit.Assert.fail(Assert.java:88)
  ...

FAILURES!!!
Tests run: 1,  Failures: 1
错误信息提示我们,期待的结果是6,但是实际输出为-6,代码88行。

Enclosed使用

采用封闭式的TestTunner的例子
通常我们需要每一个抽象类的子类,使用Enclosed runer,就可以用同一个测试用例类的静态内部类。
public class Address implements Serializable, Comparable<Address> {

    private static final long serialVersionUID = 1L;
    private final String address1;
    private final String city;
    private final String state;
    private final String zip;

    private Address(Builder builder) {
        this.address1 = builder.address1;
        this.city = builder.city;
        this.state = builder.state;
        this.zip = builder.zip;
    }

    public String getAddress1() {
        return address1;
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

    public String getZip() {
        return zip;
    }

    @Override
    public int compareTo(Address that) {
        return ComparisonChain.start().compare(this.zip, that.zip).compare(this.state, that.state)
                .compare(this.city, that.city).compare(this.address1, that.address1).result();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }
        final Address that = (Address) obj;

        return com.google.common.base.Objects.equal(this.address1, that.address1)
                && com.google.common.base.Objects.equal(this.city, that.city)
                && com.google.common.base.Objects.equal(this.state, that.state)
                && com.google.common.base.Objects.equal(this.zip, that.zip);
    }

    @Override
    public int hashCode() {
        return com.google.common.base.Objects.hashCode(getAddress1(), getCity(), getCity(), getState(), getZip());
    }

    @Override
    public String toString() {
        return com.google.common.base.Objects.toStringHelper(this).addValue(getAddress1()).addValue(getCity()).addValue(getState()).addValue(getZip()).toString();
    }

    public static class Builder {

        private String address1;
        private String city;
        private String state;
        private String zip;

        public Builder address1(String address1) {
            this.address1 = address1;
            return this;
        }

        public Address build() {
            return new Address(this);
        }

        public Builder city(String city) {
            this.city = city;
            return this;
        }

        public Builder state(String state) {
            this.state = state;
            return this;
        }

        public Builder zip(String zip) {
            this.zip = zip;
            return this;
        }
    }
}

/**
 * The Class AddressTest.
 */
@RunWith(Enclosed.class)
public class AddressTest {

    /**
     * The Class AddressComparabilityTest.
     */
    public static class AddressComparabilityTest extends ComparabilityTestCase<Address> {

        @Override
        protected Address createEqualInstance() throws Exception {
            return new Address.Builder().address1("2802 South Havana Street").city("Aurora").state("CO").zip("80014").build();
        }

        @Override
        protected Address createGreaterInstance() throws Exception {
            return new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();
        }

        @Override
        protected Address createLessInstance() throws Exception {
            return new Address.Builder().address1("14 Broad St").city("Nashua").state("NH").zip("03064").build();
        }
    }

    /**
     * The Class AddressEqualsHashCodeTest.
     */
    public static class AddressEqualsHashCodeTest extends EqualsHashCodeTestCase {

        @Override
        protected Address createInstance() throws Exception {
            return new Address.Builder().address1("2802 South Havana Street").city("Aurora").state("CO").zip("80014").build();
        }

        @Override
        protected Address createNotEqualInstance() throws Exception {
            return new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();
        }
    }

    /**
     * The Class AddressSerializabilityTest.
     */
    public static class AddressSerializabilityTest extends SerializabilityTestCase {

        @Override
        protected Serializable createInstance() throws Exception {
            return new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();
        }
    }

    public static class AddressMiscTest {

        private Address address;

        /**
         * Setup.
         *
         * @throws Exception the exception
         */
        @Before
        public void setUp() throws Exception {
            address = new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();
        }

        /**
         * Test builder.
         */
        @Test
        public void testBuilder() {
            assertThat(address.getAddress1(), is("9839 Carlisle Boulevard NE"));
            assertThat(address.getCity(), is("Albuquerque"));
            assertThat(address.getState(), is("NM"));
            assertThat(address.getZip(), is("87110"));
        }

        @Test
        public void testToString() {
            assertThat(address.toString(), is("Address{9839 Carlisle Boulevard NE, Albuquerque, NM, 87110}"));
        }
    }
}

测试套件Suite

使用Suite可以构建包含多个单元测试的套件,Junit4中使用注解,相关于JUnit3.8中的Test.suite()方法,
使用示例
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({
  TestFeatureLogin.class,
  TestFeatureLogout.class,
  TestFeatureNavigate.class,
  TestFeatureUpdate.class
})

public class FeatureTestSuite {
  // the class remains empty,
  // used only as a holder for the above annotations
}

断言方法Assert

JUnit 为基本类型和对象以及数组(基本类型或对象)提供了重载的断言方法。参数的顺序是期望值和实际值。可选的第一个值是错误情况的消息。有一个略微不同的断言是 assertThat 它需要的参数是一个可选的失败消息,实际返回值和一个 Matcher 对象。值得注意的是,预期的和实际的是相反的相比其他断言方法。
有代表性的断言方法示例
public class AssertTests {
  @Test
  public void testAssertArrayEquals() {
    byte[] expected = "trial".getBytes();
    byte[] actual = "trial".getBytes();
    org.junit.Assert.assertArrayEquals("failure - byte arrays not same", expected, actual);
  }

  @Test
  public void testAssertEquals() {
    org.junit.Assert.assertEquals("failure - strings are not equal", "text", "text");
  }

  @Test
  public void testAssertFalse() {
    org.junit.Assert.assertFalse("failure - should be false", false);
  }

  @Test
  public void testAssertNotNull() {
    org.junit.Assert.assertNotNull("should not be null", new Object());
  }

  @Test
  public void testAssertNotSame() {
    org.junit.Assert.assertNotSame("should not be same Object", new Object(), new Object());
  }

  @Test
  public void testAssertNull() {
    org.junit.Assert.assertNull("should be null", null);
  }

  @Test
  public void testAssertSame() {
    Integer aNumber = Integer.valueOf(768);
    org.junit.Assert.assertSame("should be same", aNumber, aNumber);
  }

  // JUnit Matchers assertThat
  @Test
  public void testAssertThatBothContainsString() {
    org.junit.Assert.assertThat("albumen", both(containsString("a")).and(containsString("b")));
  }

  @Test
  public void testAssertThathasItemsContainsString() {
    org.junit.Assert.assertThat(Arrays.asList("one", "two", "three"), hasItems("one", "three"));
  }

  @Test
  public void testAssertThatEveryItemContainsString() {
    org.junit.Assert.assertThat(Arrays.asList(new String[] { "fun", "ban", "net" }), everyItem(containsString("n")));
  }

  // Core Hamcrest Matchers with assertThat
  @Test
  public void testAssertThatHamcrestCoreMatchers() {
    assertThat("good", allOf(equalTo("good"), startsWith("good")));
    assertThat("good", not(allOf(equalTo("bad"), equalTo("good"))));
    assertThat("good", anyOf(equalTo("bad"), equalTo("good")));
    assertThat(7, not(CombinableMatcher.<Integer> either(equalTo(3)).or(equalTo(4))));
    assertThat(new Object(), not(sameInstance(new Object())));
  }

  @Test
  public void testAssertTrue() {
    org.junit.Assert.assertTrue("failure - should be true", true);
  }
}

Assume的使用

Assume直译为假设,是JUnit提供的一套用于判断测试用例的入参是否有业务含义的工具,如果入参不符合预期时会抛出AssumptionViolatedException,默认的BlockJUnit4ClassRunner及其子类会捕获这个异常并跳过当前测试,如果使用自定义的Runner则无法保证行为,视Runner的实现而定。 
Assume提供的验证方法包括: assumeTrue/assumeFalse、 assumeNotNull、 assumeThat、 assumeNoException 。具体含义都比较简单。

Rule的使用

定义测试方法行为的规则,JUnit4中包含两个注解@Rule和@ClassRule用于修饰Field或返回Rule的 Method,Rule是一组实现了TestRule接口的共享类,提供了验证、监视TestCase和外部资源管理等能力。JUnit提供了以下几个Rule实现,必要时也可以自己实现Rule。
Verifier: 验证测试执行结果的正确性。
ErrorCollector: 收集测试方法中出现的错误信息,测试不会中断,如果有错误发生测试结束后会标记失败。
ExpectedException: 提供灵活的异常验证功能。
Timeout: 用于测试超时的Rule。
ExternalResource: 外部资源管理。
TemporaryFolder: 在JUnit的测试执行前后,创建和删除新的临时目录。
TestWatcher: 监视测试方法生命周期的各个阶段。
TestName: 在测试方法执行过程中提供获取测试名字的能力。
示例代码太多,就不粘贴代码了,
详情:https://github.com/junit-team/junit4/wiki/Rules

抛出异常的测试

@Test(expected = IndexOutOfBoundsException.class) 
public void empty() { 
     new ArrayList<Object>().get(0); 
}
expected参数要小心使用,以上代码当抛出IndexOutOfBoundsException异常时候测试才通过。更加建议使用ExpectedException rule
@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
    List<Object> list = new ArrayList<Object>();

    thrown.expect(IndexOutOfBoundsException.class);
    thrown.expectMessage("Index: 0, Size: 0");
    list.get(0); // execution will never get past this line
}
这篇博客有详细描述 博客原文

超时处理

@Test(timeout=1000)
public void testWithTimeout() {
  ...
}
您还可以指定以毫秒为单位设置超时,如果超过了时间限制,会抛出一个超时异常。
如果测试运行超过规定的时间,会导致测试失败,JUnit将中断测试线程。
超时规则
超时规则适用在一个类中的所有测试方法
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

public class HasGlobalTimeout {
    public static String log;
    private final CountDownLatch latch = new CountDownLatch(1);

    @Rule
    public Timeout globalTimeout = Timeout.seconds(10); // 10 seconds max per method tested

    @Test
    public void testSleepForTooLong() throws Exception {
        log += "ran1";
        TimeUnit.SECONDS.sleep(100); // sleep for 100 seconds
    }

    @Test
    public void testBlockForever() throws Exception {
        log += "ran2";
        latch.await(); // will block 
    }
}


欢迎扫描二维码,关注公众账号
技术分享

JUnit单元测试

标签:

原文地址:http://blog.csdn.net/robertcpp/article/details/51712529

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!