pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

如何驗(yàn)證沒(méi)有拋出異常

How to verify that an exception was not thrown(如何驗(yàn)證沒(méi)有拋出異常)
本文介紹了如何驗(yàn)證沒(méi)有拋出異常的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!

問(wèn)題描述

在我使用 Mockito 的單元測(cè)試中,我想驗(yàn)證 NullPointerException 沒(méi)有被拋出.

In my unit test using Mockito I want to verify that NullPointerException was not thrown.

public void testNPENotThrown{
    Calling calling= Mock(Calling.class);
    testClass.setInner(calling);
    testClass.setThrow(true);

    testClass.testMethod();

    verify(calling, never()).method();
}

我的測(cè)試設(shè)置了 testClass,設(shè)置了 Calling 對(duì)象和屬性,以便該方法將拋出 NullPointerException.

My test set up the testClass, setting the Calling object and the property so that the method will throw a NullPointerException.

驗(yàn)證 Calling.method() 從未被調(diào)用.

I verify that the Calling.method() is never called.

public void testMethod(){
    if(throw) {
        throw new NullPointerException();
    }

    calling.method();
}

我想要一個(gè)失敗的測(cè)試,因?yàn)樗鼟伋鲆粋€(gè) NullPointerException,然后我想編寫(xiě)一些代碼來(lái)解決這個(gè)問(wèn)題.

I want to have a failing test because it throws a NullPointerException, and then I want to write some code to fix this.

我注意到的是測(cè)試總是通過(guò),因?yàn)闇y(cè)試方法永遠(yuǎn)不會(huì)拋出異常.

What I have noticed is that the test always passes as the exception is never thrown up the the test method.

推薦答案

tl;dr

  • JDK8 后:使用 AssertJ 或自定義 lambda 來(lái)斷言 異常 行為.

  • post-JDK8 : Use AssertJ or custom lambdas to assert exceptional behaviour.

pre-JDK8 :我會(huì)推薦舊的好 try-catch 塊.(別忘了在 catch 塊之前添加一個(gè) fail() 斷言)

pre-JDK8 : I will recommend the old good try-catch block. (Don't forget to add a fail() assertion before the catch block)

無(wú)論是 Junit 4 還是 JUnit 5.

長(zhǎng)篇大論

可以自己編寫(xiě)一個(gè)自己動(dòng)手 try-catch 塊或使用JUnit 工具(@Test(expected = ...)@Rule ExpectedException JUnit 規(guī)則特性).

It is possible to write yourself a do it yourself try-catch block or use the JUnit tools (@Test(expected = ...) or the @Rule ExpectedException JUnit rule feature).

但是這些方法并不那么優(yōu)雅,并且不能很好地與其他工具可讀性混合.此外,JUnit 工具確實(shí)存在一些缺陷.

But these ways are not so elegant and don't mix well readability wise with other tools. Moreover, JUnit tooling does have some pitfalls.

  1. try-catch 塊,您必須圍繞測(cè)試的行為編寫(xiě)塊并在 catch 塊中寫(xiě)入斷言,這可能很好,但很多發(fā)現(xiàn)這種風(fēng)格打斷了測(cè)試的閱讀流程.此外,您需要在 try 塊的末尾編寫(xiě)一個(gè) Assert.fail.否則,測(cè)試可能會(huì)錯(cuò)過(guò)斷言的一側(cè);PMDfindbugsSonar 會(huì)發(fā)現(xiàn)此類(lèi)問(wèn)題.

  1. The try-catch block you have to write the block around the tested behavior and write the assertion in the catch block, that may be fine but many find that this style interrupts the reading flow of a test. Also, you need to write an Assert.fail at the end of the try block. Otherwise, the test may miss one side of the assertions; PMD, findbugs or Sonar will spot such issues.

@Test(expected = ...) 功能很有趣,因?yàn)槟梢跃帉?xiě)更少的代碼,然后編寫(xiě)此測(cè)試據(jù)說(shuō)不太容易出現(xiàn)編碼錯(cuò)誤.但是這種方法在某些領(lǐng)域是缺乏的.

The @Test(expected = ...) feature is interesting as you can write less code and then writing this test is supposedly less prone to coding errors. But this approach is lacking in some areas.

  • 如果測(cè)試需要檢查異常的其他內(nèi)容,例如原因或消息(好的異常消息非常重要,僅擁有精確的異常類(lèi)型可能還不夠).
  • 同樣由于期望被放置在方法中,根據(jù)測(cè)試代碼的編寫(xiě)方式,測(cè)試代碼的錯(cuò)誤部分可能會(huì)引發(fā)異常,導(dǎo)致誤報(bào)測(cè)試,我不確定PMDfindbugsSonar 將對(duì)此類(lèi)代碼提供提示.

  • If the test needs to check additional things on the exception like the cause or the message (good exception messages are really important, having a precise exception type may not be enough).
  • Also as the expectation is placed around in the method, depending on how the tested code is written then the wrong part of the test code can throw the exception, leading to false-positive test and I'm not sure that PMD, findbugs or Sonar will give hints on such code.

@Test(expected = WantedException.class)
public void call2_should_throw_a_WantedException__not_call1() {
    // init tested
    tested.call1(); // may throw a WantedException

    // call to be actually tested
    tested.call2(); // the call that is supposed to raise an exception
}

ExpectedException 規(guī)則也是嘗試修復(fù)之前的警告,但使用起來(lái)感覺(jué)有點(diǎn)別扭,因?yàn)樗褂昧似谕麡邮剑?em>EasyMock 用戶(hù)非常了解這種風(fēng)格.這對(duì)某些人來(lái)說(shuō)可能很方便,但如果您遵循 行為驅(qū)動(dòng)開(kāi)發(fā) (BDD) 或 安排行為斷言 (AAA) 原則,則 ExpectedException 規(guī)則獲勝不適合那些寫(xiě)作風(fēng)格.除此之外,它可能會(huì)遇到與 @Test 方式相同的問(wèn)題,具體取決于您將期望放在哪里.

The ExpectedException rule is also an attempt to fix the previous caveats, but it feels a bit awkward to use as it uses an expectation style, EasyMock users know very well this style. It might be convenient for some, but if you follow Behaviour Driven Development (BDD) or Arrange Act Assert (AAA) principles the ExpectedException rule won't fit in those writing style. Aside from that it may suffer from the same issue as the @Test way, depending on where you place the expectation.

@Rule ExpectedException thrown = ExpectedException.none()

@Test
public void call2_should_throw_a_WantedException__not_call1() {
    // expectations
    thrown.expect(WantedException.class);
    thrown.expectMessage("boom");

    // init tested
    tested.call1(); // may throw a WantedException

    // call to be actually tested
    tested.call2(); // the call that is supposed to raise an exception
}

即使預(yù)期的異常放在測(cè)試語(yǔ)句之前,如果測(cè)試遵循 BDD 或 AAA,它也會(huì)破壞您的閱讀流程.

Even the expected exception is placed before the test statement, it breaks your reading flow if the tests follow BDD or AAA.

另外,請(qǐng)參閱關(guān)于 JUnit 的 comment 問(wèn)題ExpectedException 的作者.JUnit 4.13-beta-2 甚至棄用了這種機(jī)制:

Also, see this comment issue on JUnit of the author of ExpectedException. JUnit 4.13-beta-2 even deprecates this mechanism:

拉取請(qǐng)求 #1519:棄用 ExpectedException

Pull request #1519: Deprecate ExpectedException

方法 Assert.assertThrows 提供了一種更好的方法來(lái)驗(yàn)證異常.此外,ExpectedException 的使用在與 TestWatcher 等其他規(guī)則一起使用時(shí)容易出錯(cuò),因?yàn)樵谶@種情況下規(guī)則的順序很重要.

The method Assert.assertThrows provides a nicer way for verifying exceptions. In addition, the use of ExpectedException is error-prone when used with other rules like TestWatcher because the order of rules is important in that case.

因此,上述這些選項(xiàng)有很多注意事項(xiàng),并且顯然無(wú)法避免編碼錯(cuò)誤.

So these above options have all their load of caveats, and clearly not immune to coder errors.

  1. 在創(chuàng)建這個(gè)看起來(lái)很有希望的答案后,我意識(shí)到了一個(gè)項(xiàng)目,它是 catch-exception.

正如該項(xiàng)目的描述所說(shuō),它讓編碼人員編寫(xiě)流暢的代碼行來(lái)捕獲異常,并為后面的斷言提供這個(gè)異常.您可以使用任何斷言庫(kù),例如 Hamcrest 或 AssertJ.

As the description of the project says, it let a coder write in a fluent line of code catching the exception and offer this exception for the latter assertion. And you can use any assertion library like Hamcrest or AssertJ.

取自主頁(yè)的快速示例:

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
when(myList).get(1);

// then: we expect an IndexOutOfBoundsException
then(caughtException())
        .isInstanceOf(IndexOutOfBoundsException.class)
        .hasMessage("Index: 1, Size: 0") 
        .hasNoCause();

如您所見(jiàn),代碼非常簡(jiǎn)單,您在特定行捕獲異常,then API 是一個(gè)別名,將使用 AssertJ API(類(lèi)似于使用 assertThat(ex).hasNoCause()...).在某些時(shí)候,該項(xiàng)目依賴(lài)于 AssertJ 的祖先 FEST-Assert.看來(lái)該項(xiàng)目正在醞釀對(duì) Java 8 Lambdas 的支持.

As you can see the code is really straightforward, you catch the exception on a specific line, the then API is an alias that will use AssertJ APIs (similar to using assertThat(ex).hasNoCause()...). At some point the project relied on FEST-Assert the ancestor of AssertJ. It seems the project is brewing a Java 8 Lambdas support.

目前,這個(gè)庫(kù)有兩個(gè)缺點(diǎn):

Currently, this library has two shortcomings :

  • 在撰寫(xiě)本文時(shí),值得注意的是,該庫(kù)基于 Mockito 1.x,因?yàn)樗诤笈_(tái)創(chuàng)建了測(cè)試對(duì)象的模擬.由于 Mockito 仍未更新 此庫(kù)不能與最終類(lèi)或最終方法一起使用.即使它基于當(dāng)前版本的 Mockito 2,這也需要聲明一個(gè)全局模擬制造商 (inline-mock-maker),這可能不是你想要的,作為這個(gè)模擬制造商與普通的模擬制造商有不同的缺點(diǎn).

  • At the time of this writing, it is noteworthy to say this library is based on Mockito 1.x as it creates a mock of the tested object behind the scene. As Mockito is still not updated this library cannot work with final classes or final methods. And even if it was based on Mockito 2 in the current version, this would require to declare a global mock maker (inline-mock-maker), something that may not what you want, as this mock maker has different drawbacks that the regular mock maker.

它需要另一個(gè)測(cè)試依賴(lài)項(xiàng).

It requires yet another test dependency.

一旦庫(kù)支持 lambda,這些問(wèn)題將不適用.但是,AssertJ 工具集將復(fù)制該功能.

These issues won't apply once the library supports lambdas. However, the functionality will be duplicated by the AssertJ toolset.

綜合考慮如果不想使用catch-exception工具,我會(huì)推薦try-catch這個(gè)老好辦法塊,至少到JDK7.對(duì)于 JDK 8 用戶(hù),您可能更喜歡使用 AssertJ,因?yàn)樗峁┑目赡懿粌H僅是斷言異常.

Taking all into account if you don't want to use the catch-exception tool, I will recommend the old good way of the try-catch block, at least up to the JDK7. And for JDK 8 users you might prefer to use AssertJ as it offers may more than just asserting exceptions.

在 JDK8 中,lambda 進(jìn)入了測(cè)試場(chǎng)景,事實(shí)證明它們是斷言異常行為的一種有趣方式.AssertJ 已更新,提供了一個(gè)很好的流暢 API 來(lái)斷言異常行為.

With the JDK8, lambdas enter the test scene, and they have proved to be an interesting way to assert exceptional behaviour. AssertJ has been updated to provide a nice fluent API to assert exceptional behaviour.

還有一個(gè)帶有 AssertJ 的示例測(cè)試:

And a sample test with AssertJ :

@Test
public void test_exception_approach_1() {
    ...
    assertThatExceptionOfType(IOException.class)
            .isThrownBy(() -> someBadIOOperation())
            .withMessage("boom!"); 
}

@Test
public void test_exception_approach_2() {
    ...
    assertThatThrownBy(() -> someBadIOOperation())
            .isInstanceOf(Exception.class)
            .hasMessageContaining("boom");
}

@Test
public void test_exception_approach_3() {
    ...
    // when
    Throwable thrown = catchThrowable(() -> someBadIOOperation());

    // then
    assertThat(thrown).isInstanceOf(Exception.class)
                      .hasMessageContaining("boom");
}

  • 隨著對(duì) JUnit 5 的近乎完整的重寫(xiě),斷言已經(jīng) 改進(jìn)了 一點(diǎn),它們可能被證明是一種有趣的開(kāi)箱即用的方式來(lái)正確斷言異常.但實(shí)際上斷言 API 還是有點(diǎn)差,除了 assertThrows.

  • With a near-complete rewrite of JUnit 5, assertions have been improved a bit, they may prove interesting as an out of the box way to assert properly exception. But really the assertion API is still a bit poor, there's nothing outside assertThrows.

    @Test
    @DisplayName("throws EmptyStackException when peeked")
    void throwsExceptionWhenPeeked() {
        Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    
        Assertions.assertEquals("...", t.getMessage());
    }
    

    您注意到 assertEquals 仍然返回 void,因此不允許像 AssertJ 這樣的鏈接斷言.

    As you noticed assertEquals is still returning void, and as such doesn't allow chaining assertions like AssertJ.

    此外,如果您記得與 MatcherAssert 的名稱(chēng)沖突,請(qǐng)準(zhǔn)備好與 Assertions 遇到相同的沖突.

    Also if you remember name clash with Matcher or Assert, be prepared to meet the same clash with Assertions.

    我想總結(jié)一下,今天 (2017-03-03) AssertJ 的易用性、可發(fā)現(xiàn)的 API、快速的開(kāi)發(fā)速度以及 事實(shí)上的em> 測(cè)試依賴(lài)是 JDK8 的最佳解決方案,不管測(cè)試框架(JUnit 與否),之前的 JDK 應(yīng)該依賴(lài) try-catch 塊,即使他們覺(jué)得笨重.

    I'd like to conclude that today (2017-03-03) AssertJ's ease of use, discoverable API, the rapid pace of development and as a de facto test dependency is the best solution with JDK8 regardless of the test framework (JUnit or not), prior JDKs should instead rely on try-catch blocks even if they feel clunky.

    這篇關(guān)于如何驗(yàn)證沒(méi)有拋出異常的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

    【網(wǎng)站聲明】本站部分內(nèi)容來(lái)源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問(wèn)題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請(qǐng)聯(lián)系我們刪除處理,感謝您的支持!
  • 相關(guān)文檔推薦

    How to mock super reference (on super class)?(如何模擬超級(jí)參考(在超級(jí)類(lèi)上)?)
    Java mock database connection(Java 模擬數(shù)據(jù)庫(kù)連接)
    Mockito ClassCastException - A mock cannot be cast(Mockito ClassCastException - 無(wú)法投射模擬)
    Set value to mocked object but get null(將值設(shè)置為模擬對(duì)象但獲取 null)
    How to mock DriverManager.getConnection(...)?(如何模擬 DriverManager.getConnection(...)?)
    Mockito; verify method was called with list, ignore order of elements in list(模擬;使用列表調(diào)用驗(yàn)證方法,忽略列表中元素的順序)
    主站蜘蛛池模板: 合肥汽车充电桩_安徽充电桩_电动交流充电桩厂家_安徽科帝新能源科技有限公司 | 航空障碍灯_高中低光强航空障碍灯_民航许可认证航空警示灯厂家-东莞市天翔航天科技有限公司 | TTCMS自助建站_网站建设_自助建站_免费网站_免费建站_天天向上旗下品牌 | NMRV减速机|铝合金减速机|蜗轮蜗杆减速机|NMRV减速机厂家-东莞市台机减速机有限公司 | 厦门ISO认证|厦门ISO9001认证|厦门ISO14001认证|厦门ISO45001认证-艾索咨询专注ISO认证行业 | 超细|超微气流粉碎机|气流磨|气流分级机|粉体改性机|磨粉机|粉碎设备-山东埃尔派粉体科技 | 污水处理设备维修_污水处理工程改造_机械格栅_过滤设备_气浮设备_刮吸泥机_污泥浓缩罐_污水处理设备_污水处理工程-北京龙泉新禹科技有限公司 | 视频直播 -摄影摄像-视频拍摄-直播分发 | 轴流风机-鼓风机-离心风机-散热风扇-罩极电机,生产厂家-首肯电子 | 防渗膜厂家|养殖防渗膜|水产养殖防渗膜-泰安佳路通工程材料有限公司 | 皮带机-带式输送机价格-固定式胶带机生产厂家-河南坤威机械 | 自恢复保险丝_贴片保险丝_力特保险丝_Littelfuse_可恢复保险丝供应商-秦晋电子 | 山东钢格板|栅格板生产厂家供应商-日照森亿钢格板有限公司 | 定制奶茶纸杯_定制豆浆杯_广东纸杯厂_[绿保佳]一家专业生产纸杯碗的厂家 | 河北中仪伟创试验仪器有限公司是专业生产沥青,土工,水泥,混凝土等试验仪器的厂家,咨询电话:13373070969 | 蜘蛛车-高空作业平台-升降机-高空作业车租赁-臂式伸缩臂叉装车-登高车出租厂家 - 普雷斯特机械设备(北京)有限公司 | 湖北省煤炭供应链综合服务平台| 基本型顶空进样器-全自动热脱附解吸仪价格-AutoHS全模式-成都科林分析技术有限公司 | 韦伯电梯有限公司| 茶叶百科网-茶叶知识与茶文化探讨分享平台 | 路斯特伺服驱动器维修,伦茨伺服驱动器维修|万骏自动化百科 | 宿松新闻网 宿松网|宿松在线|宿松门户|安徽宿松(直管县)|宿松新闻综合网站|宿松官方新闻发布 | 新型锤式破碎机_新型圆锥式_新型颚式破碎机_反击式打沙机_锤式制砂机_青州建源机械 | 防腐储罐_塑料储罐_PE储罐厂家_淄博富邦滚塑防腐设备科技有限公司 | 巩义市科瑞仪器有限公司| U拓留学雅思一站式服务中心_留学申请_雅思托福培训 | (中山|佛山|江门)环氧地坪漆,停车场地板漆,车库地板漆,聚氨酯地板漆-中山永旺地坪漆厂家 | 自进式锚杆-自钻式中空注浆锚杆-洛阳恒诺锚固锚杆生产厂家 | 翰香原枣子坊加盟费多少钱-正宗枣核糕配方培训利润高飘香 | 福尔卡(北京)新型材料技术股份有限公司 | 纯化水设备-EDI-制药-实验室-二级反渗透-高纯水|超纯水设备 | 滁州高低温冲击试验箱厂家_安徽高低温试验箱价格|安徽希尔伯特 | 青岛代理记账_青岛李沧代理记账公司_青岛崂山代理记账一个月多少钱_青岛德辉财税事务所官网 | 低压载波电能表-单相导轨式电能表-华邦电力科技股份有限公司-智能物联网综合管理平台 | 酶联免疫分析仪-多管旋涡混合仪|混合器-莱普特科学仪器(北京)有限公司 | 工控机-工业平板电脑-研华工控机-研越无风扇嵌入式box工控机 | 工业废水处理|污水处理厂|废水治理设备工程技术公司-苏州瑞美迪 今日娱乐圈——影视剧集_八卦娱乐_明星八卦_最新娱乐八卦新闻 | 深圳市万色印象美业有限公司| 「银杏树」银杏树行情价格_银杏树种植_山东程锦园林 | 车载加油机品牌_ 柴油加油机厂家| 橡胶膜片,夹布膜片,橡胶隔膜密封,泵阀设备密封膜片-衡水汉丰橡塑科技公司网站 |