编写第一个JUnit测试

IAm*_*aja 10 java junit unit-testing

所以我已经阅读了官方的JUnit文档,其中包含了大量的例子,但是(和许多事情一样)我已经启动了Eclipse,我正在编写我的第一个JUnit测试,而且我在讨论一些基本的设计/概念问题.

因此,如果我WidgetUnitTest正在测试一个被调用的目标Widget,我假设我需要Widget在整个测试方法中创建相当数量的s.我应该WidgetWidgetUnitTest构造函数中还是在setUp()方法中构造这些?Widgets与测试方法的比例应该是1:1 ,还是最佳实践要求Widget尽可能重复使用s?

最后,断言/失败和测试方法之间应该存在多少粒度?一个纯粹主义者可能会争辩说,在测试方法中应该存在1对1的断言,但是在这个范例下,如果Widget有一个getter被调用getBuzz(),我最终会得到20个不同的测试方法,getBuzz()比如像

@Test
public void testGetBuzzWhenFooIsNullAndFizzIsNonNegative() { ... }
Run Code Online (Sandbox Code Playgroud)

与测试多种场景并承载大量断言的1种方法相反:

@Test
public void testGetBuzz() { ... }
Run Code Online (Sandbox Code Playgroud)

感谢一些JUnit大师的见解!

Tom*_*icz 17

图案

有趣的问题.首先 - 我在IDE中配置的终极测试模式:

@Test
public void shouldDoSomethingWhenSomeEventOccurs() throws Exception
{
    //given

    //when

    //then
}
Run Code Online (Sandbox Code Playgroud)

我总是从这个代码开始(聪明的人称之为BDD).

  • given我的测试设置中,每个测试都是唯一的.

  • when 理想情况下是一条线 - 你正在测试的东西.

  • then 应该包含断言.

我不是一个单独的断言倡导者,但是你应该只测试一个行为的单个方面.例如,如果该方法应返回某些内容并且还有一些副作用,请创建两个具有相同givenwhen部分的测试.

测试模式也包括throws Exception.这是为了处理Java中烦人的检查异常.如果你测试一些抛出它们的代码,你就不会受到编译器的困扰.当然,如果测试抛出异常则失败.

建立

测试设置非常重要.一方面,提取公共代码并将其放在setup()/ @Before方法中是合理的.但请注意,在阅读测试时(可读性是单元测试中的最大值!)很容易错过在测试用例开始时挂在某处的设置代码.因此,相关的测试设置(例如,您可以以不同的方式创建窗口小部件)应该转到测试方法,但是应该提取基础设施(设置常见的模拟,启动嵌入式测试数据库等).再次提高可读性.

您是否也知道JUnit每次测试都会创建测试用例类的新实例?因此,即使您在构造函数中创建了CUT(测试中的),也会在每次测试之前调用构造函数.有点烦人.

粒度

首先命名您的测试,并考虑您要测试的用例或功能,从不考虑以下方面:

这是一个Foobar()buzz()方法所以我FooTesttestBar()和创建testBuzz().哦,亲爱的,我需要测试两个执行路径bar()- 所以让我们创建testBar1()testBar2().

shouldTurnOffEngineWhenOutOfFuel()很好,testEngine17()很糟糕.

更多关于命名

testGetBuzzWhenFooIsNullAndFizzIsNonNegative名称对测试有何意义?我知道它会测试一些东西,但为什么呢?你不觉得细节太贴心吗?怎么样:

@Test shouldReturnDisabledBuzzWhenFooNotProvidedAndFizzNotNegative`
Run Code Online (Sandbox Code Playgroud)

它以有意义的方式描述输入和您的意图(假设禁用的蜂鸣声是某种buzz状态/类型).另请注意,我们不再硬编码getBuzz()方法名称和null合同Foo(相反,我们说:何时Foo未提供).如果将来nullnull对象模式替换怎么办?

也不要害怕20种不同的测试方法getBuzz().请考虑您正在测试的20个不同的用例.但是,如果您的测试用例类增长得太大(因为它通常比测试类大得多),请提取几个测试用例.再次:FooHappyPathTest,FooBogusInput并且FooCornerCases很好,Foo1Test而且Foo2Test很糟糕.

可读性

争取简短和描述性的名字.少数几行given和几行then.而已.创建构建器和内部DSL,提取方法,编写自定义匹配器和断言.测试应该比生产代码更具可读性.不要过度嘲笑.

我发现首先编写一系列空的,命名良好的测试用例方法很有用.然后我回到第一个.如果我仍然明白我想在什么条件下测试什么,我在此期间实现构建类API的测试.然后我实现了那个API.聪明人称之为TDD(见下文).

推荐阅读: