Thông thường, trong Unit Test, chúng ta sẽ sử dụng các Mocking framework như Mockito, PowerMock để giả lập cách mà các đối tượng sẽ thực thi khi code Unit Test của chúng ta gọi đến các phương thức của chúng. Tương tự như vậy, trong Mule ESB, chúng ta cũng có Mock component được sử dụng trong MUnit để giả lập cách mà các endpoint trong một Mule Flow sẽ thực thi. Cụ thể như thế nào? Chúng ta hãy cùng nhau tìm hiểu trong bài viết này các bạn nhé!
Đầu tiên, mình sẽ tạo một Mule Maven project để làm ví dụ:
với Mule Flow có nội dung như sau:
Mule Flow này sẽ cho phép người dùng có thể truy cập đến ứng dụng của chúng ta và truyền một request parameter tên là name. Sau đó, Mule Flow của chúng ta sẽ gọi đến một SOAP Web Service mà mình đã hiện thực trong bài viết này, để có thể trả về kết quả cho người dùng dòng chữ với giá trị “Hello, ” + giá trị của parameter name.
Trong đó:
HTTP Listener Connector được cấu hình để client có thể truy cập ứng dụng của chúng ta bằng địa chỉ http://localhost:8082/mock.
Các bạn có thể xem thêm cách cấu hình của HTTP Listener Connector tại đây. Người dùng có thể truyền parameter name bằng cách request như sau: http://localhost:8082/mock?name=Khanh.
Tranform Message đầu tiên sẽ có nhiệm vụ build request message để gửi tới SOAP Web Service.
SOAP Web Service mà mình sử dụng được hiện thực ở bài viết Tạo SOAP Web Service sử dụng CXF component trong Mule ESB, do đó, Tranform Message sẽ có nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 |
%dw 1.0 %output application/xml %namespace hdj http://muleesbcxfsoapexpose.huongdanjava.com/ --- { hdj#hello: { arg0: inboundProperties."http.query.params".name } } |
Tiếp theo là phần cấu hình cho Web Service Consumer component.
Mình đã chạy SOAP Web Service trong bài viết Tạo SOAP Web Service sử dụng CXF component trong Mule ESB ở địa chỉ http://localhost:8081/hello với tập tin WSDL có nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
This XML file does not appear to have any style information associated with it. The document tree is shown below. <wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://muleesbcxfsoapexpose.huongdanjava.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloWorldServiceService" targetNamespace="http://muleesbcxfsoapexpose.huongdanjava.com/"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://muleesbcxfsoapexpose.huongdanjava.com/" elementFormDefault="unqualified" targetNamespace="http://muleesbcxfsoapexpose.huongdanjava.com/" version="1.0"> <xs:element name="hello" type="tns:hello" /> <xs:element name="helloResponse" type="tns:helloResponse" /> <xs:complexType name="hello"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="xs:string" /> </xs:sequence> </xs:complexType> <xs:complexType name="helloResponse"> <xs:sequence> <xs:element minOccurs="0" name="return" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="helloResponse"> <wsdl:part element="tns:helloResponse" name="parameters"></wsdl:part> </wsdl:message> <wsdl:message name="hello"> <wsdl:part element="tns:hello" name="parameters"></wsdl:part> </wsdl:message> <wsdl:portType name="HelloWorldService"> <wsdl:operation name="hello"> <wsdl:input message="tns:hello" name="hello"></wsdl:input> <wsdl:output message="tns:helloResponse" name="helloResponse"></wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloWorldServiceServiceSoapBinding" type="tns:HelloWorldService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="hello"> <soap:operation soapAction="" style="document" /> <wsdl:input name="hello"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="helloResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloWorldServiceService"> <wsdl:port binding="tns:HelloWorldServiceServiceSoapBinding" name="HelloWorldServicePort"> <soap:address location="http://localhost:8081/hello" /> </wsdl:port> </wsdl:service> </wsdl:definitions> |
Do đó Web Service Consumer sẽ có cấu hình như sau:
Global Configuration:
với tập tin hello.wsdl nằm trong thư mục src/main/resource nha các bạn!
Sau khi nhận response từ SOAP Web Service, mình sẽ sử dụng Transform Message để lấy message cần trả về cho người dùng.
Message response từ SOAP Web Service sẽ có nội dung như sau:
1 2 3 4 |
<?xml version="1.0" encoding="UTF-8"?> <ns2:helloResponse xmlns:ns2="http://muleesbcxfsoapexpose.huongdanjava.com/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <return>Hello, Khanh</return> </ns2:helloResponse> |
Message cần trả về cho người dùng có nội dung “Hello, Khanh” nên mình sẽ cấu hình cho Transform Message này như sau:
1 2 3 4 5 6 7 8 |
%dw 1.0 %output application/java %namespace ns0 http://muleesbcxfsoapexpose.huongdanjava.com/ --- payload.ns0#helloResponse.return |
Endpoint cuối cùng mà mình sử dụng là Huong Dan Java Logger để log nội dung message cần trả về cho người dùng.
Cấu hình của Huong Dan Java Logger như sau:
Global Configuration:
Lúc này, nếu các bạn chạy ứng dụng này thì sẽ thấy kết quả như sau:
OK, bây giờ chúng ta sẽ sử dụng MUnit để viết Unit Test cho Mule Flow của chúng ta các bạn nhé!
Như mình đã giới thiệu với các bạn về MUnit trong bài viết này, mình sẽ tạo một tập tin MUnit với nội dung ban đầu như sau:
Set Message component sẽ giúp chúng ta tạo một request message với Inbound Property giúp chúng ta có thể truyền một request với parameter là name với giá trị là Khanh.
Cấu hình của nó như sau:
Assert Equals sẽ assert nội dung trả về cho người dùng với nội dung mà chúng ta mong muốn.
Trong ví dụ này thì nội dung của Assert Equals sẽ như sau:
Bây giờ, chúng ta sẽ đi vào phần quan trọng nhất trong bài viết này.
Như các bạn thấy, nếu chạy bình thường để test ứng dụng thì SOAP Web Service của chúng ta http://localhost:8081/hello có sẵn để chúng ta có thể chạy được. Nhưng khi chạy MUnit, phần lớn là SOAP Web Service này không tồn tại. Để đảm bảo là chúng ta có thể chạy MUnit ở bất cứ đâu, bắt buộc chúng ta phải giả lập nó với Mock component của Mule ESB.
Để làm điều này, các bạn hãy tìm kiếm trong Mule Palete Mock component:
rồi sau đó kéo thả vào phần Setup của MUnit như sau:
Phần cấu hình cho Mock component sẽ có nội dung như sau:
Có 2 thứ chúng ta cần cấu hình cho Mock component đó là: chúng ta cần giả lập cho endpoint nào trong Mule Flow và khi đó, giá trị trả về sẽ là gì?
Tất cả các cấu hình trên sẽ nằm trong phần Matching Processor Condition của Mock component.
Để chọn endpoint nào cần giả lập, các bạn hãy nhấp vào nút search bên cạnh ô “When message processor matches” rồi chọn đến Web Service Consumer, như sau:
còn phần giá trị trả về là gì, chúng ta sẽ cấu hình trong ô “Then return message with payload”.
Đối với những giá trị trả về đơn giản, các bạn có thể nhập giá trị này trực tiếp vào ô này luôn, nhưng do giá trị trả về trong bài viết này hơi nhiều nên mình sẽ sử dụng cách khác. Đó là mình sẽ sử dụng MEL với phương thức getResource() để lấy nội dung trả về từ một tập tin, như sau:
Như các bạn thấy, mình đã sử dụng phương thức getResource() với tham số là tên tập tin chứa giá trị trả về. Tập tin này nằm trong thư mục /src/test/resources các bạn nhé! Sau khi lấy nội dung của tập tin data.xml, chúng ta có thể convert nội dung tập tin qua String như mình đã làm ở trên, ngoài ra chúng ta còn có thể convert nội dung tập tin thành Stream hoặc ByteArray như sau.
1 2 |
#[getResource('data.xml').asStream()] #[getResource('data.xml').asByteArray()] |
Việc chọn MIME type cũng rất quan trọng để chỉ định định dạng của payload.
Bây giờ thì các bạn có thể chạy MUnit mà chúng ta vừa viết để kiểm tra kết quả: