AxonFramework測試

CQRS最大的好處之一,尤其是事件溯源就事件和命令而言,單純地表達(dá)測試是可能的朝巫。這兩個功能組件,事件和命令對領(lǐng)域?qū)<一驑I(yè)務(wù)所有者都有明確的含義石景。這不僅意味著測試表達(dá)就事件和命令而言有明確的功能含義劈猿,這也意味著他們不依靠任何實現(xiàn)選擇。

本章描述的特性需要axon-test模塊,可通過配置maven依賴(使用<artifactId>axon-test</artifactId> 和<scope>test</scope)或通過完整包下載潮孽。

本章中描述的固件可用于任何測試框架揪荣,如JUnit和TestNG。

命令組件測試

在任何CQRS基礎(chǔ)架構(gòu)中命令處理組件通常是最復(fù)雜的往史。比其他組件更復(fù)雜仗颈,這也意味著該組件有額外的與測試相關(guān)的需求。

雖然更復(fù)雜椎例,但是命令的API處理組件相當(dāng)容易挨决。它有一個命令進來请祖,然后事件出去。在某些情況下脖祈,可能有一個查詢作為命令執(zhí)行的一部分肆捕。除此之外,命令和事件是API的唯一部分盖高。這意味著可以在事件和命令的基礎(chǔ)上完整地定義測試場景福压。典型地,以:
? given過去的某些事件或舞,
? when 執(zhí)行這個命令荆姆,
? expect 這些事件將被發(fā)布和/或存儲

Axon Framework提供了一個測試固件映凳,使你能夠做到這一點胆筒。AggregateTestFixture允許你配置某些基礎(chǔ)設(shè)施,包括必要的命令處理器和存儲庫诈豌,并以given-when-then形式的事件和命令來表達(dá)你的場景仆救。

下面的示例展示了用JUnit 4對given-when-then測試固件的使用:

public class MyCommandComponentTest {
 private FixtureConfiguration fixture;
 @Before
 public void setUp() {
     fixture = new AggregateTestFixture(MyAggregate.class);
 }

 @Test
 public void testFirstFixture() {
     fixture.given(new MyEvent(1))
            .when(new TestCommand())
            .expectSuccessfulHandlerExecution()
            .expectEvents(new MyEvent(2));
     /*
     These four lines define the actual scenario and its expected
     result. The first line defines the events that happened in the
     past. These events define the state of the aggregate under test.
     In practical terms, these are the events that the event store
     returns when an aggregate is loaded. The second line defines the
     command that we wish to execute against our system. Finally, we
     have two more methods that define expected behavior. In the
     example, we use the recommended void return type. The last method
     defines that we expect a single event as result of the command
     execution.
     /*
 }
}

given-when-then測試固件定義了三個階段:配置、執(zhí)行和驗證矫渔。每個階段由不同的接口表示:分別是彤蔽,F(xiàn)ixtureConfiguration, TestExecutor 和 ResultValidator。固件類的靜態(tài)newGivenWhenThenFixture()方法提供了對第一個的引用庙洼,進而可能提供驗證顿痪,等等。

注意
為了最好地利用這些階段之間的遷移油够,最好使用這些方法提供的流式接口蚁袭,如上面的示例所示。

在配置階段(即在提供第一個“given”之前)石咬,你提供了執(zhí)行測試所需的構(gòu)件揩悄。作為固件的一部分提供事件總線、命令總線和事件存儲的專用版本鬼悠。有accessor方法來獲得對它們的引用删性。任何命令處理器不直接在聚合上注冊,需要顯式地使用registerAnnotatedCommandHandler 方法配置焕窝。除了帶注解的命令處理器外蹬挺,你還可以配置各種組件和設(shè)置,定義應(yīng)該如何設(shè)置測試周圍的基礎(chǔ)設(shè)施袜啃。

一旦固件配置好汗侵,你就可以定義“given”事件。測試固件將用DomainEventMessage包裝這些事件群发。如果“given”事件實現(xiàn)消息晰韵,消息的有效負(fù)載和元數(shù)據(jù)將被納入DomainEventMessage,否則given事件作為有效負(fù)載熟妓。DomainEventMessage 的序列號順序雪猪,從0開始。

或者起愈,你也可以為“given”場景提供命令只恨。在這種情況下,在執(zhí)行實際的測試命令時抬虽,這些命令生成的事件將被用于事件源聚合官觅。使用“givenCommands(…)”方法提供命令對象。

執(zhí)行階段允許你提供一個針對命令處理組件執(zhí)行的命令阐污。對調(diào)用處理程序的行為(無論是在聚合或外部處理程序)進行監(jiān)控休涤,并與在驗證階段注冊的預(yù)期進行比較。

注意
在執(zhí)行測試過程中笛辟,Axon試圖檢測測試中的所有在聚合上的非法狀態(tài)的更改功氨。它通過將聚合的狀態(tài)與命令執(zhí)行后的聚合狀態(tài)進行比較,如果它從所有“given”和存儲的事件溯源手幢。如果狀態(tài)不相同捷凄,這意味著狀態(tài)變化發(fā)生在聚合事件處理器方法之外。比較時將忽略靜態(tài)和瞬態(tài)字段围来,因為它們通常包含對資源的引用跺涤。
可以使用setReportIllegalStateChange方法在固件的配置中切換檢測。

最后一個階段是驗證階段监透,允許你檢查命令處理組件的活動钦铁。這完全是根據(jù)返回值和事件來完成的。

測試固件允許你驗證命令處理程序的返回值才漆。你可以顯式地定義預(yù)期的返回值牛曹,或者簡單地要求成功返回該方法。你也可以表達(dá)任何你期望的CommandHandler拋出的異常醇滥。

另一個組件是對已發(fā)布事件的驗證黎比。有兩種匹配預(yù)期事件的方法。

第一是通過事件實例鸳玩,它需要與實際的事件是行逐字的比較阅虫。將預(yù)期事件的所有屬性與實際事件中的對應(yīng)對象進行比較(使用equals())。如果其中一個屬性不相等不跟,則測試失敗颓帝,并生成一個廣泛的錯誤報告。

表達(dá)期望的另一種方式是使用的匹配器(Hamcrest庫提供的)。匹配器接口規(guī)定了兩個方法matches(Object)和describeTo(Description)购城。第一個返回一個布爾值吕座,指示是否匹配或不匹配。第二個讓你表達(dá)你的期望瘪板。例如吴趴,一個“GreaterThanTwoMatcher”可以添加“任何值大于2的事件“的描述。描述允許創(chuàng)建關(guān)于測試用例失敗的錯誤消息侮攀。

創(chuàng)建事件列表的匹配器可能是繁瑣和容易出錯的工作锣枝。為了簡化問題,Axon提供了一組匹配器允許你提供一組特定于事件的匹配器兰英,并告訴Axon應(yīng)該如何匹配列表撇叁。

下面是可用的事件列表匹配器和他們的目的的概述:

  • List with all of: Matchers.listWithAllOf(event matchers...)
    如果所有的事件匹配器與真實事件列表中至少一個事件匹配,該匹配器將成功畦贸。不管是否有多個匹配器匹配相同的事件陨闹,或如果列表中一個事件不匹配任何匹配器。

  • List with any of: Matchers.listWithAnyOf(event matchers...)
    如果一個或多個事件匹配器與實際的事件列表中一個或多個事件匹配家制,該匹配器將成功正林。一些匹配器甚至一個也不匹配,而另一個匹配多個颤殴。

  • Sequence of Events: Matchers.sequenceOf(event matchers...)
    使用此匹配器來驗證實際事件匹配器和提供的事件匹配器有相同的順序觅廓。如果匹配器與后一個事件相匹配,與前一個匹配器匹配的事件相匹配涵但,該匹配器將成功杈绸。這意味著可能出現(xiàn)不匹配事件的“gaps”。
    如果評估事件之后矮瘟,更多的匹配器是可用的瞳脓,他們都是匹配“null”。它是由事件的匹配器來決定是否接受澈侠。

  • Exact sequence of Events: Matchers.exactSequenceOf(event matchers...)
    “事件的序列”匹配器的變化不允許不匹配事件的空隙劫侧。這意味著每個匹配器必須與事件后面的事件相匹配,與前一個匹配器匹配的事件相匹配。每個匹配器都應(yīng)該與它前一個匹配器相對應(yīng)的事件的后續(xù)一個事件相匹配

為了方便起見,提供了一些普遍需要的事件匹配器。他們與單個事件實例相匹配:

  • Equal Event: Matchers.equalTo(instance...)
    驗證given對象在語義上等于given事件镣陕,這個匹配器將比較實際和預(yù)期的對象的所有字段的值使用一個null-safe相等方法笛臣。這意味著可以比較事件馅笙,即使它們不實現(xiàn)equals方法。存儲在given參數(shù)字段上的對象用equals進行比較,要求他們正確實現(xiàn)。

  • No More Events: Matchers.andNoMore() or Matchers.nothing()
    僅與空值匹配魔吐,這個匹配器可以作為最后一個匹配器添加到事件的準(zhǔn)確順序匹配器,以確保沒有不匹配的事件依然存在扎筒。

由于匹配器傳遞一個事件消息列表,有時你只是想驗證消息的有效負(fù)載酬姆。有匹配器來幫助你:

  • Payload Matching: Matchers.messageWithPayload(payload matcher)
    驗證消息的有效負(fù)載匹配給定的有效載荷匹配器嗜桌。

  • Payloads Matching: Matchers.payloadsMatching(list matcher)
    驗證消息的有效負(fù)載匹配給定的有效載荷匹配器。給定的匹配器必須匹配列表包含的每個消息的有效負(fù)載轴踱。有效負(fù)載匹配匹配器通常用作外匹配器,以防止重復(fù)有效負(fù)載匹配器症脂。

下面是一個簡單的代碼示例谚赎,以顯示這些匹配器的使用淫僻。在這個例子中,我們預(yù)期共有兩個事件發(fā)布。第一個事件必須是一個“ThirdEvent”壶唤,第二個是“aFourthEventWithSomeSpecialThings”雳灵。可能沒有第三個事件闸盔,因為那樣"andNoMore"匹配器會失敗悯辙。

fixture.given(new FirstEvent(), new SecondEvent())
       .when(new DoSomethingCommand("aggregateId"))
       .expectEventsMatching(exactSequenceOf(
           // we can match against the payload only:
           messageWithPayload(equalTo(new ThirdEvent())),
           // this will match against a Message
           aFourthEventWithSomeSpecialThings(),
           // this will ensure that there are no more events
           andNoMore()
       ));

// or if we prefer to match on payloads only:
       .expectEventsMatching(payloadsMatching(
               exactSequenceOf(
                   // we only have payloads, so we can equalTo directly
                   equalTo(new ThirdEvent()),
                   // now, this matcher matches against the payload too
                   aFourthEventWithSomeSpecialThings(),
                   // this still requires that there is no more events
                   andNoMore()
               )
       ));
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市迎吵,隨后出現(xiàn)的幾起案子躲撰,更是在濱河造成了極大的恐慌,老刑警劉巖击费,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拢蛋,死亡現(xiàn)場離奇詭異,居然都是意外死亡蔫巩,警方通過查閱死者的電腦和手機谆棱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圆仔,“玉大人垃瞧,你說我怎么就攤上這事∑汗” “怎么了个从?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長歪沃。 經(jīng)常有香客問我嗦锐,道長,這世上最難降的妖魔是什么绸罗? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任意推,我火速辦了婚禮,結(jié)果婚禮上珊蟀,老公的妹妹穿的比我還像新娘菊值。我一直安慰自己外驱,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布腻窒。 她就那樣靜靜地躺著昵宇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪儿子。 梳的紋絲不亂的頭發(fā)上瓦哎,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音柔逼,去河邊找鬼蒋譬。 笑死,一個胖子當(dāng)著我的面吹牛愉适,可吹牛的內(nèi)容都是我干的犯助。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼维咸,長吁一口氣:“原來是場噩夢啊……” “哼剂买!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起癌蓖,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤瞬哼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后租副,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坐慰,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年附井,在試婚紗的時候發(fā)現(xiàn)自己被綠了讨越。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡永毅,死狀恐怖把跨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沼死,我是刑警寧澤着逐,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站意蛀,受9級特大地震影響耸别,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜县钥,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一秀姐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧若贮,春花似錦省有、人聲如沸痒留。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伸头。三九已至,卻和暖如春舷蟀,著一層夾襖步出監(jiān)牢的瞬間恤磷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工野宜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扫步,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓速缨,卻偏偏與公主長得像锌妻,于是被迫代替她去往敵國和親代乃。 傳聞我的和親對象是個殘疾皇子旬牲,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)搁吓,斷路器原茅,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • 文章來自:http://blog.csdn.net/mj813/article/details/52451355 ...
    好大一只鵬閱讀 9,189評論 2 126
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,778評論 6 342
  • 作為一株車前草她很是不能理解,什么時候車前草也能修煉成精了堕仔,何況她什么都沒做就莫名的幻成人形了擂橘,她覺得很是對...
    煌箜閱讀 287評論 10 3
  • 人生已經(jīng)過去半,知道美好的年華老去摩骨,不用在曲意逢迎通贞,知道自己責(zé)任,也知道自己愛好恼五,只想做自己的喜歡的有意義的事
    東東少閱讀 179評論 0 1