REST・SOAP・(MQ) テストツール SoapUI を使ってみた
REST と SOAP のテストツールに SoapUI というものがあります.
REST のテストツールというと Postman/Newman が有名かと思いますが、SoapUI さんも中々に高機能でして、
- Windows/Mac/Linux で実行可能
- REST と SOAP の両方に対応している
- HermsJMS をインストールすれば MQ も使える
- API Driver/Stub の両方の役割をこなせる
- テストケースを設定してアサーションできる
- shell/bat で起動できる
このようにオールインワンで何でもこなせるテストツールになっています.
(REST/SOAP/MQ 全部こなせるのはデリバリー現場で非常に嬉しい)
ソースコードも公開されているので、何かあっても自分で調べられる安心感があります.
GitHub – SmartBear/soapui
Open Source版とPro版があります.
Pro版はテスト結果をExcelに出力するなど付加機能がたくさんありますが、Open Source版でも十分に使えるレベルです.
今回は SoapUI を REST で使ってみたいと思います.
サンプルプログラム
Spring Boot のサンプルを用意しました.
package com.projectrespite.soapuidemo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
@ApiModel(value = "Person", description = "This entity is person which have id, name and age fields.")
public class Person {
@ApiModelProperty(value = "ID", example = "279818d8-89d0-43b2-9c62-a397b6a4ce50", required = true, position = 0)
private String id;
@ApiModelProperty(value = "Name", example = "箱崎太郎", required = true, position = 1)
private String name;
@ApiModelProperty(value = "Age", example = "20", required = true, position = 2)
private int age;
}
package com.projectrespite.soapuidemo;
import org.springframework.stereotype.Repository;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Repository
public class PersonRepository {
public List getPeople(){
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject("http://localhost:8081/external/v1/people", List.class);
}
}
package com.projectrespite.soapuidemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ExternalApiService {
@Autowired
private PersonRepository repository;
public List getPeople(){
List people = repository.getPeople();
people.add(new Person("f95db0bc-7f8a-493c-95d5-0af08f38a10a", "箱崎花子", 30));
return people;
}
}
package com.projectrespite.soapuidemo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/v1")
@Api(value = "/api/v1", tags = "Get people data")
public class ExternalApiController {
@Autowired
private ExternalApiService service;
@GetMapping("people")
@ApiOperation(value = "get people data", notes = "API returns all people data.")
public List getPeople(){
return service.getPeople();
}
}
外部 API から JSON データを取得し、要素を追加した上でレスポンスを返します.
package com.projectrespite.soapuidemo;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.VendorExtension;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("SoupUI Demo API")
.select()
.paths(paths())
.build()
.apiInfo(apiInfo())
.directModelSubstitute(OffsetDateTime.class, java.util.Date.class)
.directModelSubstitute(LocalDate.class, java.sql.Date.class)
.protocols(new HashSet(Arrays.asList("http", "https")));
}
private Predicate paths() {
return Predicates.or(Predicates.containsPattern("/api"));
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SoapUI Demo API")
.description("This is SoapUI Demo API.")
.version("v1")
.termsOfServiceUrl("https://www.project-respite.com/api/terms")
.contact(new Contact("Project Respite",
"https://www.project-respite.com",
"email@project-respite.com"))
.license("API LICENSE")
.licenseUrl("https://www.project-respite.com/api/license")
.extensions(new ArrayList())
.build();
}
}
Swagger ファイルから Driver を生成したいので、Swagger 定義を追加しました.
Swagger ファイル取得
Swagger UI から Swagger ファイルを取得します.
http://localhost:8080/v2/api-docs?group=SoupUI%20Demo%20API
SoapUI の操作
ここから SoapUI の操作を行なっていきます.
まずはプロジェクトを作成します.
Swagger ファイルをインポートします.
ファイルを選択します.
Swagger ファイルから Driver を作成できました.
次に Stub を作成します.
REST の Mock Service を作成します.
Stub のホスト名およびポートを指定します.
Mock Action を作成します.
メソッドとエンドポイントを指定します.
レスポンスを作成します.
Stub として返したいレスポンスを指定します.
最後にテストケースを作成します.
まずはテストスイート(複数のテストケースの単位)を作成します.
テストケースを作成します.
次に Stub を起動するスクリプトを作成します.
スクリプトは Groovy で書きます.
スクリプトを記述します.
testRunner.testCase.testSuite.project.getRestMockServiceByName("External API").start()
API 呼び出し(Driver)を作成します.
Driver 定義から呼び出したい API を選択します.
左上のプラスボタンからアサーションを追加します.
JSON Path Match を選択します.
配列の1番目の要素の id 属性にアサートします.
テスト実行
まずは GUI から実行してみます.
テストが正常に実行されました.
テストが失敗するとこのように表示されます.
次に shell から実行してみます.
shell で実行する場合、/Users/USER_NAME/.soapuios/plugins を参照できないバグがあるのか、エラーが出てしまいますので、plugins を何かしらにリネームすることをおすすめします.
How to resolve Auto Discovery Method Factory Error or Auto Import Method Factory in your newly created Soap UI-Jenkins Job?
$ export PATH=/Applications/SoapUI-5.5.0.app/Contents/java/app/bin:$PATH
$ testrunner.sh "SoapUI-Demo-soapui-project.xml"
================================
=
= SOAPUI_HOME = /Applications/SoapUI-5.5.0.app/Contents/java/app
=
================================
SoapUI 5.5.0 TestCase Runner
20:40:36,514 INFO [DefaultSoapUICore] initialized soapui-settings from [/Users/aa367474/soapui-settings.xml]
20:40:38,024 INFO [PluginManager] 0 plugins loaded in 5 ms
20:40:38,024 INFO [DefaultSoapUICore] All plugins loaded
20:40:40,509 INFO [WsdlProject] Loaded project from [file:/Users/aa367474/Desktop/SoapUI-Demo-soapui-project.xml]
20:40:40,521 INFO [SoapUITestCaseRunner] Running SoapUI tests in project [SoapUI Demo]
20:40:40,522 INFO [SoapUITestCaseRunner] Running Project [SoapUI Demo], runType = SEQUENTIAL
20:40:40,542 INFO [SoapUITestCaseRunner] Running SoapUI testcase [TestCase]
20:40:40,553 INFO [SoapUITestCaseRunner] running step [Mock Start Script]
20:40:41,428 INFO [JettyMockEngine] Started mockService [External API] on port [8081] at path [/external]
20:40:41,432 INFO [SoapUITestCaseRunner] running step [REST Request]
20:40:41,707 DEBUG [HttpClientSupport$SoapUIHttpClient] Attempt 1 to execute request
20:40:41,707 DEBUG [SoapUIMultiThreadedHttpConnectionManager$SoapUIDefaultClientConnection] Sending request: GET /api/v1/people HTTP/1.1
20:40:41,917 DEBUG [SoapUIMultiThreadedHttpConnectionManager$SoapUIDefaultClientConnection] Receiving response: HTTP/1.1 200
20:40:41,924 DEBUG [HttpClientSupport$SoapUIHttpClient] Connection can be kept alive indefinitely
20:40:42,326 INFO [SoapUITestCaseRunner] Assertion [ID Match 1] has status VALID
20:40:42,327 INFO [SoapUITestCaseRunner] Assertion [Name Match 1] has status VALID
20:40:42,328 INFO [SoapUITestCaseRunner] Assertion [Age Match 1] has status VALID
20:40:42,328 INFO [SoapUITestCaseRunner] Assertion [ID Match 2] has status VALID
20:40:42,329 INFO [SoapUITestCaseRunner] Assertion [Name Match 2] has status VALID
20:40:42,329 INFO [SoapUITestCaseRunner] Assertion [Age Match 2] has status VALID
20:40:42,329 INFO [SoapUITestCaseRunner] running step [Mock Release Script]
20:40:42,347 INFO [JettyMockEngine] Stopped MockService [External API] on port [8081]
20:40:42,350 INFO [SoapUITestCaseRunner] Finished running SoapUI testcase [TestCase], time taken: 1254ms, status: FINISHED
20:40:42,351 INFO [SoapUITestCaseRunner] Project [SoapUI Demo] finished with status [FINISHED] in 1821ms
shell からもテストが実行できました.
まとめ
今回は SoapUI を使ってみました.
繰り返しになりますが、以下のような利点から非常に実用的なツールかと思います.
- Windows/Mac/Linux で実行可能
- REST と SOAP の両方に対応している
- HermsJMS をインストールすれば MQ も使える
- API Driver/Stub の両方の役割をこなせる
- テストケースを設定してアサーションできる
- shell/bat で起動できる
shell で実行できることからも、自動テストにも組み込めるかと思います.
とても便利なツールですね!
以上です.