【第7回】マイクロサービスの結合試験コード実装

マイクロサービスにおける結合テスト


前回は、マイクロサービス(Backend)の単体テストの実装例や検証観点、テスト戦略のポイントを説明しました。 今回はバックエンドで実行されるマイクロサービスの結合テストです。アプリケーションおよびテストのパッケージ・コンポーネント構成は前回と同様、以下としています。


[backend]
  └src
    ├main
    │ ├java
    │ │ └org
    │ │   └debugroom
    │ │     └mynavi
    │ │       └sample
    │ │         └continuous
    │ │           └integration
    │ │             └backend
    │ │               └app                                  ... アプリケーション層のパッケージ
    │ │               │ └model                              ... リクエストパラメータのモデルクラスパッケージ
    │ │               │ │ ├Xxxxx.java                       ... 入力チェックルール等が定義されるモデルクラス
    │ │               │ │ └XxxxxMapper.java                 ... ドメイン層のモデルクラスと相互変換するマッパークラス
    │ │               │ └web                                ... MvcConfigでコンポーネントスキャンの対象とするパッケージ
    │ │               │   └BackendRestController.java       ... リクエストハンドリング・ドメインサービス呼び出して、Resourceを返却するコントローラクラス
    │ │               └domain                               ... ドメイン層のパッケージ
    │ │               │ └model
    │ │               │ │ └entity                           ... JPAConfigでスキャン対象とするエンティティクラスパッケージ
    │ │               │ │   └Xxxxx.java                     ... JPAエンティティクラス
    │ │               │ ├repository                         ... JPAConfigでスキャン対象とするレポジトリクラスパッケージ
    │ │               │ │ ├specification                    ... JPAでテーブル結合等の条件を指定するクラスパッケージ
    │ │               │ │ │ └Xxxxx.java                     ... JPAでテーブル結合等の条件を指定するクラス
    │ │               │ │ └XxxxxRepository.java             ... レポジトリインタフェースクラス
    │ │               │ └service                            ... DomainConfigでコンポーネントスキャンの対象とするサービスクラスパッケージ
    │ │               │   ├SampleService.java               ... DBへ基本的なCRUDアクセスを行うサービスインタフェースクラス
    │ │               │   ├SampleServiceImpl.java           ... SampleServiceの実装クラス
    │ │               │   ├SampleOneToOneService.java       ... 1対1の関連をもつテーブルアクセスを行うサービスインタフェースクラス
    │ │               │   ├SampleOneToOneServiceImpl.java   ... SampleOneToOneServiceの実装クラス
    │ │               │   ├SampleOneToManyService.java      ... 1対多の関連をもつテーブルアクセスを行うサービスインタフェースクラス
    │ │               │   ├SampleOneToManyServiceImpl.java  ... SampleOneToOneServiceの実装クラス
    │ │               │   ├SampleManyToManyService.java     ... 多対多の関連をもつテーブルアクセスを行うサービスインタフェースクラス
    │ │               │   └SampleManyToManyServiceImpl.java ... サービス実装クラス
    │ │               └config                               ... 設定クラス用のパッケージ
    │ │                   ├App.java                         ... アプリケーション起動クラス
    │ │                   ├DevConfig.java                   ... 開発環境固有の設定クラス
    │ │                   ├DomainConfig.java                ... ドメイン層に関する設定クラス
    │ │                   ├JPAConfig.java                   ... JPA設定クラス
    │ │                   └MvcConfig.java                   ... アプリケーション層に関する設定クラス
    │ └resources
    │   ├application.yml                                    ... アプリケーション設定ファイル
    │   └application-dev.yml                                ... プロファイル"dev"で有効になるアプリケーション設定ファイル
    test                                                    ... テストパッケージフォルダ
      ├java
      │ └org
      │   └debugroom
      │     └mynavi
      │       └sample
      │         └continuous
      │           └integration
      │             └backend
      │               ├app
      │               │ └web
      │               │   └BackendRestControllerTest.java   ... Controllerのテストクラス
      │               ├domain
      │               │ ├DataJpaTestConfig.java             ... Repositoryのテスト設定クラス
      │               │ ├repository                         ... Repositoryテストパッケージ
      │               │ │ └XxxxRepositoryTest.java          ... Repositoryのテストクラス
      │               │ └service                            ... Serviceテストパッケージ
      │               │   └XxxxServiceTest.java             ... Serviceのテストクラス
      │               └config
      │                 └TestConfig.java                    ... Testの汎用設定クラス
      └resources
        ├META-INF
        │ └dbunit                                           ... DBUnitのテーブルデータ用パッケージ
        │   └domain
        │     └service
        │       └XxxxServiceTest                            ... テストクラスごとのフォルダ
        │         └Xxxx                                     ... テストケースごとのフォルダ
        │           ├Xxxxx.csv                              ... 各テーブルのテストデータ
        │           └table-ordering.txt                     ... 読み込み対象のテーブル名を記載したテキストファイル
        └application.yml                                    ... テスト用のアプリケーション設定ファイル


各コンポーネントは TERASOLUNAのガイドライン レイヤの依存関係 を基本的に踏襲していますが、Controller→Service→Repositoryという単方向の呼び出ししかありません。 そのため、結合試験としては、下記のイメージ通り、Service→Repositoryおよび、Controller→Service→Repositoryといった順に積み上げ式で試験を進めることにします(Repositoryをスタブ化し、ControllerとServiceのみの結合試験は除外できます)。


../_images/microservice-integrationtest-scope.png


各テストの観点は以下の通りです。コンポーネントの内部構造は意識せず、ブラックボックス的に処理実行後のIOやデータベース反映結果を中心に検証します。


アプリケーション 試験 コンポーネント 検証観点
マイクロサービス
(Backend)
結合試験 Service⇔Repository ・データベースから正しく値が取得できるか
・データベースへ正しくデータが反映できるか
・設定ファイルが正しく動作するか
    Controller⇔Service⇔Repository ・期待したレスポンスが返却されるか
・モデル間のデータマッピングが正しく実行されているか
・設定ファイルが正しく動作するか


Service⇔Repositoryの結合テスト実装


データベースからの基本的なデータ取得については、Repositoryの単体テストで妥当性確認はとれているので、データベースへの更新結果を中心にDBUnitを用いて検証します(複雑な条件のデータ取得は処理結合レベルでバリエーションテストを実施した方がよりベターです)。 また、Serviceの単体でも分岐条件などで発生するビジネスエラーや設定されるメッセージの確認はとれているので、ServiceがRepositoryを正しく呼び出すことができるか、 プロパティなどの設定が正しく動作するかを@SpringBootTestアノテーションを使って、SpringBootApplicationを起動した場合のように検証します。 Serviceクラスを起点としたサンプル結合テストコードは以下の通りです。


package org.debugroom.mynavi.sample.continuous.integration.backend.domain.service;

// omit
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import com.github.springtestdbunit.annotation.ExpectedDatabases;
import com.github.springtestdbunit.assertion.DatabaseAssertionMode;
import com.github.springtestdbunit.dataset.AbstractDataSetLoader;

import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.csv.CsvDataSet;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;

// omit

@RunWith(SpringRunner.class)                                                 // …(A)
@SpringBootTest(classes = {
      TestConfig.ServiceTestConfig.class,
}, webEnvironment =  SpringBootTest.WebEnvironment.NONE)                     // …(B)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
      DirtiesContextTestExecutionListener.class,
      TransactionalTestExecutionListener.class,
      DbUnitTestExecutionListener.class })                                   // …(C)
@DbUnitConfiguration(dataSetLoader = IntegrationTest.CsvDataSetLoader.class) // …(D)
@ActiveProfiles("dev")
public static class IntegrationTest{

    public static class CsvDataSetLoader extends AbstractDataSetLoader{  // …(E)
        @Override
        protected IDataSet createDataSet(Resource resource) throws Exception {
            return new CsvDataSet(resource.getFile());
        }
    }

    // omit

    @Autowired
    SampleService sampleService;

    @Test
    @ExpectedDatabases({                                                       // …(F)
          @ExpectedDatabase(
                  value = "classpath:/META-INF/dbunit/domain/service/SampleServiceImplTest/add",
                  table = "usr", assertionMode = DatabaseAssertionMode.NON_STRICT),
          @ExpectedDatabase(
                  value = "classpath:/META-INF/dbunit/domain/service/SampleServiceImplTest/add",
                  table = "address", assertionMode = DatabaseAssertionMode.NON_STRICT),
          @ExpectedDatabase(
                  value = "classpath:/META-INF/dbunit/domain/service/SampleServiceImplTest/add",
                  table = "email", assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED),
          @ExpectedDatabase(
                  value = "classpath:/META-INF/dbunit/domain/service/SampleServiceImplTest/add",
                  table = "membership", assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED),
    })
    public void addNormalTest() throws BusinessException{
        // omit
        User addUser = User.builder()
              .firstName("saburo")
              .familyName("mynavi")
              .loginId("saburo.mynavi")
              .isLogin(false)
              .addressByUserId(addAddress)
              .emailsByUserId(Arrays.asList(new Email[]{addEmail1, addEmail2}))
              .membershipsByUserId(Arrays.asList(new Membership[]{membership1}))
              .build();
       sampleService.add(addUser);
    }


Service⇔Repositoryの結合テストコードの説明
項番 説明
テストランナーとして、SpringRunnerを指定します。
@SpringBootTestアノテーションには、テスト向け固有の設定クラスを任意に指定し、Controllerを介さない場合、Webコンテナ(Server)を起動しないオプションを指定しておきます。
DBUnitで使用するTestExecutionListenerの設定を行います。ここでは詳しい説明は割愛しますが、詳細は TERASOLUNAガイドライン TestExecutionListenerの登録 を参照してください。
テストに使うデータベースへのデータ設定にはCSV形式のデータファイルを使用します。なお、データはExcel形式でもできますが、実行パフォーマンスの問題やコードコミット時にバイナリファイルで差分比較ができなくなるためCSVの方がベターです。詳細は テストデータのセットアップ を参照してください。
CSV形式でデータロードするための拡張クラスです。
テストメソッド実行後に期待するデータベースのデータを各テーブルごとに設定します。詳細は Spring Test DBUnitを利用したテスト も参照してください。


サンプルとして実装したテストケースと検証観点は以下になります。テストケースの順序をうまく設定すること(AddしてからFindAllする)でトランザクションの有効化なども合わせて、処理結合テストレベルで検証するようにしています。 なお、下記のように、プロファイル"dev"で有効化する設定クラスを作成し、データベースおよびテストデータは事前にHSQLなどのインメモリDBに設定しておきます。


package org.debugroom.mynavi.sample.continuous.integration.backend.config;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

@Profile("dev")
@Configuration
public class DevConfig {

    @Bean
    public DataSource dataSource(){
        return (new EmbeddedDatabaseBuilder())
          .setType(EmbeddedDatabaseType.HSQL)
          .addScript("classpath:ddl/schema.sql")
          .addScript("classpath:ddl/data.sql")
          .build();
    }
}


ユースケース 主な処理実装クラス・メソッド
テストメソッド
検証観点
[正常系]ユーザを追加する SampleService#add

SampleServiceTest#addNormalTest()
・データベースへ正しくデータが反映できるか
[正常系]ユーザを検索する SampleService#findOne

SampleServiceTest#findOneNormalTest()
・データベースから正しく値が取得できるか
・(Autowiredインジェクション等)設定が正しいか
[正常系]全ユーザを検索する SampleService#findAll

SampleServiceTest#findAllNormalTest()
・(トランザクション)設定が正しいか
[正常系]ユーザを更新する SampleService#update

SampleServiceTest#updateNormalTest()
・データベースへ正しくデータが反映できるか(想定した部分以外まで更新されていないか)
[正常系]ユーザを削除する SampleService#delete

SampleServiceTest#deleteNormalTest()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)
[正常系]指定したユーザの住所を取得する SampleOneToOneService#findAddressOf

SampleOneToOneServiceTest#findAddressOfNormalTest()
・データベースから正しく値が取得できるか
・(Autowiredインジェクション等)設定が正しいか
[正常系]指定した郵便番号の住所をもつユーザを取得する(1) SampleOneToOneService#findUserHavingAddressOfZipCode

SampleOneToOneServiceTest#findUserHavingAddressOfZipCodeNormalTest1()
・データベースから正しく値が取得できるか
[正常系]指定した郵便番号の住所をもつユーザを取得する(2) SampleOneToOneService#findUserHavingAddressOfZipCode

SampleOneToOneServiceTest#findUserHavingAddressOfZipCodeNormalTest2()
・データベースから正しく値が取得できるか
[正常系]指定した郵便番号の住所をもたないユーザを取得する(1) SampleOneToOneService#findUserHavingAddressOfZipCode

SampleOneToOneServiceTest#findUserHavingAddressOfZipCodeNormalTest1()
・データベースから正しく値が取得できるか
[正常系]指定した郵便番号の住所をもたないユーザを取得する(2) SampleOneToOneService#findUserHavingAddressOfZipCode

SampleOneToOneServiceTest#findUserHavingAddressOfZipCodeNormalTest2()
・データベースから正しく値が取得できるか
[正常系]住所を更新する。 SampleOneToOneService#update

SampleOneToOneServiceTest#updateTestNormal()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)
[正常系]指定したユーザのメールリストを取得する SampleOneToManyService#getEmailsOf

SampleOneToManyServiceTest#getEmailsOfNormalTest()
・データベースから正しく値が取得できるか
・(Autowiredインジェクション等)設定が正しいか
[正常系]メールを追加する。 SampleOneToManyService#add

SampleOneToManyServiceTest#addNormalTest()
・データベースへ正しくデータが反映できるか
[正常系]メールを更新する。 SampleOneToManyService#update

SampleOneToManyServiceTest#updateNormalTest()
・データベースへ正しくデータが反映できるか(想定した部分以外まで更新されていないか)
[正常系]メールを削除する(1)。 SampleOneToManyService#delete

SampleOneToManyServiceTest#deleteNormalTest1()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)
[正常系]メールを削除する(2)。 SampleOneToManyService#delete

SampleOneToManyServiceTest#deleteNormalTest2()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)
[正常系]全てのメールを削除する。 SampleOneToManyService#deleteAll

SampleOneToManyServiceTest#deleteAllNormalTest()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)
[正常系]ユーザが所属するグループを取得する SampleManyToManyService#getGroupOf

SampleManyToManyServiceTest#getGroupOfUserNormalTest()
・データベースから正しく値が取得できるか
・(Autowiredインジェクション等)設定が正しいか
[正常系]指定したグループに所属するユーザを取得する SampleManyToManyService#getUserOf

SampleManyToManyServiceTest#getUserOfGroupNormalTest()
・データベースから正しく値が取得できるか
[正常系]指定したグループに所属しないユーザを取得する SampleManyToManyService#getUserOfNot

SampleManyToManyServiceTest#getUserOfNotGroupNormalTest()
・データベースから正しく値が取得できるか
[正常系]指定したグループにユーザを追加する SampleManyToManyService#addUserTo

SampleManyToManyServiceTest#addUserToGroupNormalTest()
・データベースへ正しくデータが反映できるか
[正常系]指定したグループからユーザを削除する SampleManyToManyService#deleteUserFrom

SampleManyToManyServiceTest#deleteUserFromGroupNormalTest()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)
[正常系]指定したグループを削除する SampleManyToManyService#delete

SampleManyToManyServiceTest#deleteGroupNormalTest()
・データベースへ正しくデータが反映できるか(想定した部分以外まで削除されていないか)


Controller⇔Service⇔Repositoryの結合テスト実装


Controller⇔Service⇔Repositoryの結合テストでは、実際にアプリケーションを起動した時と同様、HTTPリクエストを送信し、期待したHTTPレスポンスが返ってくるか検証します。 データベースへの反映結果は前節のService⇔Repositoryで確認が取れているので、Service実行後のアウトプットが期待した通り、HTTPレスポンスに変換されるか、モデルのデータマッピングが正しく実行されているか、アプリケーションの設定が正しく動作するかといった点が主な観点になります。 Controllerクラスを起点とした結合テストサンプルコードは以下の通りです。

package org.debugroom.mynavi.sample.continuous.integration.backend.app.web;

// omit

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;

// omit

@RunWith(SpringRunner.class)                                      // …(A)
@SpringBootTest(classes = TestConfig.ControllerTestConfig.class,
   webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)    // …(B)
public static class IntegrationTest{

    private static final String testServer = "localhost";

    @Autowired
    TestRestTemplate testRestTemplate;                           // …(C)

    @LocalServerPort
    int port;                                                    // …(D)

    private String testServerURL;

    @Before
    public void setUp(){
        testServerURL = "http://" + testServer + ":" + port;     // …(E)
    }

    @Test
    public void getUsersNormalTest(){
        ResponseEntity<UserResource[]> responseEntity = testRestTemplate
          .getForEntity(testServerURL + "/api/v1/users", UserResource[].class);

        List<UserResource> userResources = Arrays.asList(responseEntity.getBody());

        assertThat(userResources.size(), is(3));
        userResources.forEach(userResource -> {
            switch (Long.toString(userResource.getUserId())){
                case "1":
                    assertThat(userResource.getFirstName(), is("hanako"));
                    assertThat(userResource.getFamilyName(), is("mynavi"));
                    break;
                // omit
            }
        });

   }


Controller⇔Service⇔Repositoryの結合テストコードの説明
項番 説明
テストランナーとして、SpringRunnerを指定します。
@SpringBootTestアノテーションには、テスト向け固有の設定クラスを任意に指定し、Webコンテナ(Server)の起動時のポートをランダムで指定しておきます。
起動したテストアプリケーションに対して、リクエストを送信するTestRestTemplateをインジェクションします。
(B)でランダム指定したポートを取得します。
セットアップメソッドで、HTTPリクエストを送信するテストサーバURLを作成します。


サンプルとして実装したテストケースと検証観点は以下になります。異常系のバリエーションは単体テストで検証しているため、 基本的には、エラー時のHTTPレスポンス生成が正しく実行されるかといった点のみを検証しています。


ユースケース 主な処理実装クラス・メソッド
テストメソッド
検証観点
[正常系]ユーザの一覧を取得する BackendController#getUsers

BackendControllerTest#getUsersNormalTest()
・期待したレスポンスが返却されるか
・設定ファイルが正しく動作するか
[正常系]ユーザを取得する BackendController#getUser

BackendControllerTest#getUserNormalTest()
・期待したレスポンスが返却されるか

・モデル間のデータマッピングが正しく実行されているか
[異常系]ユーザを取得する BackendController#getUser

BackendControllerTest#getUserAbnormalTest()
・期待したレスポンスが返却されるか(エラー)
[正常系]ユーザを追加する BackendController#addUser

BackendControllerTest#addUserNormalTest()
・期待したレスポンスが返却されるか
[正常系]ユーザを更新する BackendController#updateUser

BackendControllerTest#updateUserNormalTest()
・期待したレスポンスが返却されるか
[正常系]ユーザを削除する BackendController#deleteUser

BackendControllerTest#deleteUserNormalTest()
・期待したレスポンスが返却されるか
[正常系]指定したログインIDを持つユーザを検索する BackendController#findUserOfLoginId

BackendControllerTest#findUserOfLoginIdNormalTest()
・期待したレスポンスが返却されるか
[正常系]指定したユーザの住所を取得する BackendController#findAddressOfUser

BackendControllerTest#findAddressOfUserNormalTest()
・期待したレスポンスが返却されるか

・モデル間のデータマッピングが正しく実行されているか
[正常系]指定した郵便番号の住所を持つユーザを検索する BackendController#findUsersHavingAddressOfZipCode

BackendControllerTest#findUsersHavingAddressOfZipCodeNormalTest()
・期待したレスポンスが返却されるか
[正常系]指定した郵便番号の住所を持たないユーザを検索する BackendController#findUsersNotHavingAddressOfZipCode

BackendControllerTest#findUsersNotHavingAddressOfZipCodeNormalTest()
・期待したレスポンスが返却されるか
[正常系]住所を更新する BackendController#updateAddress

BackendControllerTest#updateAddressNormalTest()
・期待したレスポンスが返却されるか
[正常系]指定したユーザのメールアドレスリストを取得する BackendController#findEmailsOfUser

BackendControllerTest#findEmailsOfUserNormalTest()
・期待したレスポンスが返却されるか

・モデル間のデータマッピングが正しく実行されているか
[正常系]指定したメールアドレスをもつユーザを取得する BackendController#findUserHavingEmail

BackendControllerTest#findUserHavingEmailNormalTest()
・期待したレスポンスが返却されるか
[正常系]メールアドレスを追加する BackendController#addEmail

BackendControllerTest#addEmailNormalTest()
・期待したレスポンスが返却されるか
[正常系]メールアドレスを更新する BackendController#updateEmail

BackendControllerTest#updateEmailNormalTest()
・期待したレスポンスが返却されるか
[正常系]メールアドレスを削除する BackendController#deleteEmail

BackendControllerTest#deleteEmailNormalTest()
・期待したレスポンスが返却されるか
[正常系]ユーザが所属するグループを取得する BackendController#findGroupsOfUser

BackendControllerTest#findGroupsOfUserNormalTest()
・期待したレスポンスが返却されるか

・モデル間のデータマッピングが正しく実行されているか
[正常系]指定したグループに所属するユーザを取得する BackendController#findUsersOfGroup

BackendControllerTest#findUsersOfGroupNormalTest()
・期待したレスポンスが返却されるか
[正常系]指定したグループに所属しないユーザを取得する BackendController#findUsersOfNotGroup

BackendControllerTest#findUsersOfNotGroupNormalTest()
・期待したレスポンスが返却されるか
[正常系]ユーザを指定したグループに追加する BackendController#addUserToGroup

BackendControllerTest#addUserToGroupNormalTest()
・期待したレスポンスが返却されるか
[正常系]ユーザを指定したグループから削除する BackendController#deleteUserFromGroup

BackendControllerTest#deleteUserFromGroupNormalTest()
・期待したレスポンスが返却されるか
[正常系]グループを削除する BackendController#deleteGroup

BackendControllerTest#deleteGroupNormalTest()
・期待したレスポンスが返却されるか


マイクロサービスにおける結合テスト戦略と品質評価


(1)Service⇔Repository、(2)Controller⇔Service⇔Repositoryの結合テストコード実装を解説してきました。単体テストと似通った試験を実施しても非効率になりますので、効率的な結合テスト戦略策定のポイントとしては、

  • コンポーネントの内部構造は意識せず、ブラックボックス的に処理実行後のInputOutputやデータベース反映結果を中心に検証する。
  • テストケースの順序をうまく設定すること(AddしてからFindAllするなど)でトランザクションの有効化なども合わせて、処理結合テストレベルで検証する。
  • 探索的テストを導入し、実装状況に応じてテストケースの重複を極力減らしながらテストコードを作成する
  • 機能や処理の重要度に応じて、テスト実施内容に濃淡をつける(ビジネス的にそこまで重要でない処理の参照系はテストしない等)

テストクラスの量を増やしたくないのであれば、(1)を除外して、(2)で(1)のテスト観点を含めて検証しても問題ありません。 テスト品質は、ユースケース数に対するテストケースの割合、テストケースの定性的評価などを加えつつ評価するとよいでしょう。


次回は引き続き、マイクロサービスを呼び出すWebアプリケーションにおいて、単体テストコードをSpringBootでどのように実装するか、解説していきます。


著者紹介

川畑 光平(KAWABATA Kohei) - NTTデータ 課長代理

../_images/pic_image01.jpg

金融機関システム業務アプリケーション開発・システム基盤担当を経て、現在はソフトウェア開発自動化関連の研究開発・推進に従事。

Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなど様々な開発プロジェクト支援にも携わる。

2019 APN AWS Top Engineers & Ambassadors 選出。