Junit 4 学习汇总

1.断言assert

JUnit为所有基本类型和对象和数组(基元或对象)提供重载的断言方法。参数顺序是预期值,后跟实际值。第一个参数可以是失败时输出的String消息(可选)。断言略有不同,assertThat它具有可选失败消息,实际值和Matcher对象的参数。请注意,与其他断言方法相比,预期和实际相反。具体api查看github :https://github.com/junit-team/junit4/wiki/Assertions

  @Test
  public void testAssertArrayEquals() {
    byte[] expected = "trial".getBytes();
    byte[] actual = "trial".getBytes();
    assertArrayEquals("failure - byte arrays not same", expected, actual);
  }

2.组合测试

使用Suite可以手动构建包含许多类测试的套件。要使用它,请使用@RunWith(Suite.class)和注释一个类@SuiteClasses(TestClass1.class, ...)。借助一个空类来运行所有包含的测试类的所有方法

@RunWith(Suite.class)
@Suite.SuiteClasses({
        UserControllerTest.class,
        User.class,
})

public class FeatureTestSuite {
    
}

3.Junit执行顺序

根据设计,JUnit不指定测试方法调用的执行顺序。到目前为止,这些方法只是按反射API返回的顺序调用。但是,使用JVM顺序是不明智的,因为Java平台没有指定任何特定顺序,实际上JDK 7返回或多或少的随机顺序。从版本4.11开始,JUnit将默认使用确定性但不可预测的顺序(MethodSorters.DEFAULT)。要更改测试执行顺序,只需使用@FixMethodOrder并指定一个可用的MethodSorters 来注释您的测试类:

  • @FixMethodOrder(MethodSorters.JVM):按JVM返回的顺序保留测试方法。此订单可能因运行而异。
  • @FixMethodOrder(MethodSorters.NAME_ASCENDING):按字典顺序按方法名称对测试方法进行排序。
@FixMethodOrder(MethodSorters.DEFAULT)
public class TestMethodOrder {

    @Test
    public void testA() {
        System.out.println("first");
    }
    @Test
    public void testB() {
        System.out.println("second");
    }
    @Test
    public void testC() {
        System.out.println("third");
    }
}

4.异常测试

如何验证代码是否按预期抛出异常?验证代码是否正常完成非常重要,但确保代码在特殊情况下的行为符合预期也至关重要。

下方demo表示如果抛出异常则测试正常通过

@Test(expected = IndexOutOfBoundsException.class)
public void empty() {
    new ArrayList<Object>().get(0);
}

使用@Rule定义异常规则,当符合预期规则的时候则正常运行 

public class TestExy {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void shouldThrow() {
        TestThing testThing = new TestThing();
        thrown.expect(NotFoundException.class);
        thrown.expectMessage(startsWith("some Message"));
        thrown.expect(hasProperty("response", hasProperty("status", is(404))));
        testThing.chuck();
    }

    private class TestThing {
        public void chuck() {
            Response response = Response.status(Status.NOT_FOUND).entity("Resource not found").build();
            throw new NotFoundException("some Message", response);
        }
    }
}

5.断言匹配

具可读性和可输入性:这种语法允许您根据主语,动词,对象(断言“x是3”)来思考,而不是assertEquals使用动词,对象,主语(断言“等于3 x”)

组合:任何匹配器语句都可以是negated(not(s)),combined(either(s).or(t)),映射到集合(each(s)),或用于自定义组合(afterFiveSeconds(s)

assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));
assertThat(responseString, anyOf(containsString("color"), containsString("colour")));

6.忽略测试

忽略JUnit中的测试,您可以注释方法或删除@Test注释; 但是测试运行员不会报告这样的测试。或者,您可以@Ignore在前面或后面添加注释@Test。测试运行器将报告被忽略的测试数量,以及运行的测试数量和失败的测试数量。

    @Test
    @Ignore("Test is ignored as a demonstration")
    public void testA() {
        System.out.println("first");
    }

7.测试超时

测试“失控”或耗时太长,可能会自动失败。有两种方法可以实现此行为:

 @Test(timeout = 1000)
    public  void testWithTimeout() throws InterruptedException {
        Thread.sleep(2000);
    }

使用@Rule时候,将会对本类的所有方法进行超时规则测试 

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
    }
}

8.参数化测试

自定义运行器Parameterized实现参数化测试。运行参数化测试类时,将会通过参数构造不同的实例并且进行单元测试

当拥有构造器的时候,成员变量可以不加#@Parmeter注解

@RunWith(Parameterized.class)
public class FibonacciTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {     
                 { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }  
           });
    }

    private int fInput;

    private int fExpected;

    public FibonacciTest(int input, int expected) {
        this.fInput = input;
        this.fExpected = expected;
    }

    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}

当没有构造器的时候,将会使用@Parameter 分别设置成员变量,记得默认为0,所以如果有多个参数要按照顺序写上序号 

@RunWith(Parameterized.class)
public class FibonacciTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                 { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }  
           });
    }

    @Parameter // first data value (0) is default
    public /* NOT private */ int fInput;

    @Parameter(1)
    public /* NOT private */ int fExpected;

    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}

public class Fibonacci {
    public static int compute(int n) {
    	int result = 0;
    	
        if (n <= 1) { 
        	result = n; 
        } else { 
        	result = compute(n - 1) + compute(n - 2); 
        }
        
        return result;
    }
}

单个参数的测试

@Parameters
public static Iterable<? extends Object> data() {
    return Arrays.asList("first test", "second test");
}

@Parameters
public static Object[] data() {
    return new Object[] { "first test", "second test" };
}

9.假设

理想情况下,编写测试的开发人员可以控制可能导致测试失败的所有力。如果不能立即实现,那么明确依赖关系通常可以改进设计。例如,如果测试在与开发人员预期不同的语言环境中运行时失败,则可以通过将语言环境显式传递给域代码来修复它。

   @Test 
    public void filenameIncludesUsername() {
        assumeThat(1, is(0));
        System.out.println("I'm here"); // 这句不会被执
    }

10.RULE规则

@Rule 代表的是一个重写了@Before和@After的类,由于一些公用的@Before方法可以提取出来,所以有了rule

TemporaryFolder

TemporaryFolder类是junit提供的关于文件的默认类,提供了文件创建和文件删除的功能

public static class HasTempFolder {
  @Rule
  public final TemporaryFolder folder = new TemporaryFolder();

  @Test
  public void testUsingTempFolder() throws IOException {
    File createdFile = folder.newFile("myfile.txt");
    File createdFolder = folder.newFolder("subfolder");
    // ...
  }
} 

从源码可以看出,在进行单元测试的时候,会执行before和after的方法 

    protected void after() {
        this.delete();
    }

    public void create() throws IOException {
        this.folder = this.createTemporaryFolderIn(this.parentFolder);
    }

    public void delete() {
        if (this.folder != null) {
            this.recursiveDelete(this.folder);
        }

    }
    public void create() throws IOException {
        this.folder = this.createTemporaryFolderIn(this.parentFolder);
    }

 ErrorCollector 

用于收集异常信息,不会因为一个异常而终止程序运行

public  class UsesErrorCollectorTwice {
    @Rule
    public final ErrorCollector collector = new ErrorCollector();

    @Test
    public void example() {
        collector.addError(new Throwable("first thing went wrong"));
        collector.addError(new Throwable("second thing went wrong"));
    }
}

 TestWatcher

有点类似监听单元测试的运行状态,可以再程序的成功或者失败的时候调用某些方法

public class WatchmanTest {
  private static String watchedLog;

  @Rule
  public final TestRule watchman = new TestWatcher() {
    @Override
    public Statement apply(Statement base, Description description) {
      return super.apply(base, description);
    }

    @Override
    protected void succeeded(Description description) {
      watchedLog += description.getDisplayName() + " " + "success!\n";
    }

    @Override
    protected void failed(Throwable e, Description description) {
      watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n";
    }

    @Override
    protected void skipped(AssumptionViolatedException e, Description description) {
      watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n";
    }

    @Override
    protected void starting(Description description) {
      super.starting(description);
    }

    @Override
    protected void finished(Description description) {
      super.finished(description);
    }
  };

  @Test
  public void fails() {
    fail();
  }

  @Test
  public void succeeds() {
  }
}

TestName

用于获取当前测试单元的方法名

public class NameRuleTest {
    @Rule
    public final TestName name = new TestName();

    @Test
    public void testA() {
        assertEquals("testA", name.getMethodName());
    }

    @Test
    public void testB() {
        assertEquals("testB", name.getMethodName());
    }
}

Timeout

给所有方法第一个超时时间

public static class HasGlobalTimeout {
  public static String log;
  
  @Rule
  public final TestRule globalTimeout = Timeout.millis(20);
  
  @Test
  public void testInfiniteLoop1() {
    log += "ran1";
    for(;;) {}
  }
  
  @Test
  public void testInfiniteLoop2() {
    log += "ran2";
    for(;;) {}
  }
}

其他请参考github 

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

11.Theroy 

没看懂

12.Test fixtures

大概是在单元测试的前后,类启动的前后进行一些方法的调用

public class TestFixturesExample {
    static class ExpensiveManagedResource implements Closeable {
        @Override
        public void close() throws IOException {}
    }

    static class ManagedResource implements Closeable {
        @Override
        public void close() throws IOException {}
    }

    @BeforeClass
    public static void setUpClass() {
        System.out.println("@BeforeClass setUpClass");
        myExpensiveManagedResource = new ExpensiveManagedResource();
    }

    @AfterClass
    public static void tearDownClass() throws IOException {
        System.out.println("@AfterClass tearDownClass");
        myExpensiveManagedResource.close();
        myExpensiveManagedResource = null;
    }

    private ManagedResource myManagedResource;
    private static ExpensiveManagedResource myExpensiveManagedResource;

    private void println(String string) {
        System.out.println(string);
    }

    @Before
    public void setUp() {
        this.println("@Before setUp");
        this.myManagedResource = new ManagedResource();
    }

    @After
    public void tearDown() throws IOException {
        this.println("@After tearDown");
        this.myManagedResource.close();
        this.myManagedResource = null;
    }

    @Test
    public void test1() {
        this.println("@Test test1()");
    }

    @Test
    public void test2() {
        this.println("@Test test2()");
    }
}

13.分类组合测试

从下面的注释和注解可以非常容易看出是通过接口来进行方法的分类

public interface FastTests { /* category marker */ }
public interface SlowTests { /* category marker */ }

public class A {
  @Test
  public void a() {
    fail();
  }

  @Category(SlowTests.class)
  @Test
  public void b() {
  }
}

@Category({SlowTests.class, FastTests.class})
public class B {
  @Test
  public void c() {

  }
}

@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public class SlowTestSuite {
  // Will run A.b and B.c, but not A.a
}

@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@ExcludeCategory(FastTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public class SlowTestSuite {
  // Will run A.b, but not A.a or B.c
}

猜你喜欢

转载自blog.csdn.net/m0_37834471/article/details/83036328