そこに仁義はあるのか(仮)

略してそこ仁!

他のクラスへの「呼び出し回数」と「引数として渡した値」をテストする

久しぶりにテストコードを書いたのでMEMO〜。

アプリから他のサービスを使っているけど、自動テストの時はそのサービスを使いたくない。
もしくは、テスト対象のクラスから他のクラスのメソッドを呼び出しているが、他のクラスの仕様はそのクラスのテストに委譲しており、今回のテストには含めたくない。
ただ、作成したクラスからサービスや他のクラスに対して、どんな値が渡されたのかはチェックしたい。

f:id:syobochim:20190630163339p:plain:w500

例えば、Controllerクラスのテストをする場合、 Controller内で Fukuzatsu クラスの hikisuIppai()メソッドを呼び出しているとする。
でも、hikisuIppai()メソッドの挙動は Fukuzatsu クラス側でテストするから、hikisuIppai() メソッドの「呼び出し回数」「引数として渡された値」が想定通りに設定されていることだけをテストできればOKとする。
そうした時のテストクラスはこんな感じになる。

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.web.servlet.MockMvc;

import java.math.BigDecimal;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

@AutoConfigureMockMvc
@SpringBootTest
class ControllerTest {
  @Autowired
  private MockMvc mockMvc;
  @SpyBean
  private Fukuzatsu fukuzatsu;
  @Captor
  private ArgumentCaptor<Hotel> hotel;
  @Captor
  private ArgumentCaptor<Reservation> reservation;

  @Test
  void detailTest(@Autowired ObjectMapper mapper) throws Exception {
    doReturn(null).when(this.fukuzatsu).hikisuIppai(any(), any(), any(), any());

    CreateCommand cmd = new CreateCommand(hoge, fuga, piyo);
    String json = mapper.writeValueAsString(cmd);
    mockMvc.perform(post("/detail").content(json));

    verify(this.fukuzatsu, times(1)).hikisuIppai(any(), hotel.capture(), reservation.capture(), any());
    assertThat(reservation.getValue().getRating(), allOf(greaterThanOrEqualTo(new BigDecimal(0)), lessThanOrEqualTo(new BigDecimal(5))));
    assertThat(reservation.getValue().getNumberOfPeople(), is(greaterThanOrEqualTo(0)));
  }
}

内部の処理をスキップさせるために@SpyBean を利用して Fukuzatsu クラスの hikisuIppai メソッドの処理をモック化している。
今回は、引数に何が来ても null を返すように。

  @SpyBean
  private Fukuzatsu fukuzatsu;

...

    doReturn(null).when(this.fukuzatsu).hikisuIppai(any(), any(), any(), any());

アサーションでは、 hikisuIppai メソッドの呼び出し回数と、引数として渡した値を検査している。
キャプチャできれば普通に is メソッドなどを使って比較ができる。 今回は、

  • hikisuIppaiメソッドの呼び出し回数が1回であること
  • hikisuIppai メソッドの2番目、3番目に渡した値が想定通りであること
    • 2番目の値は hotel プロパティにキャプチャして、 hotel.getValue() で値を取得している。
    • 3番目の値は reservation プロパティにキャプチャして、 reservation.getValue() で値を取得している。

を検査している。

  @Captor
  private ArgumentCaptor<Hotel> hotel;
  @Captor
  private ArgumentCaptor<Reservation> reservation;

...

    verify(this.fukuzatsu, times(1)).hikisuIppai(any(), hotel.capture(), reservation.capture(), any());
    assertThat(hotel.getValue().getRating(), allOf(greaterThanOrEqualTo(new BigDecimal(0)), lessThanOrEqualTo(new BigDecimal(5))));
    assertThat(reservation.getValue().getNumberOfPeople(), is(greaterThanOrEqualTo(0)));

Spring BootのアプリとOracle CloudのAutonomous Databaseを接続する - アプリケーション編

Oracle Code Tokyoでハンズオンのお手伝いをしてきました!
ハンズオンは、Rails / laravel / Django / Spring Bootの4つのフレームワークを利用して、Oracle CloudのAutonomous Transaction Processingサービス(Oracle 18c)へ接続するサンプルアプリと、その手順を作っています。
私はSpring Boot(JPAを利用)のサンプルアプリとハンズオン手順、また、それに合わせてアプリの検証環境構築用のTerraformも作りました。

ハンズオンの手順やアプリはこちらのGitHubリポジトリに置いています。
ハンズオン手順と内容がかぶるところも多いのですが、この機会に、環境の作り方やデータベース接続方法などを整理したいと思います。

github.com

今回は、いよいよ完結編。アプリケーション作成のポイントを書いていこうと思います。
構成や環境構築編の内容についてはこちら
Spring BootのアプリとOracle CloudのAutonomous Databaseを接続する - 環境構築編 - そこに仁義はあるのか(仮)
アプリケーションの設定についてはこちら
Spring BootのアプリとOracle CloudのAutonomous Databaseを接続する - アプリケーション環境編 - そこに仁義はあるのか(仮)


f:id:syobochim:20190520002319p:plain

  • 👌 アプリで使っているもの
  • 👌 pom.xml
  • 👌 データベース接続設定を追加
  • 👌 シーケンスの設定
続きを読む

Spring BootのアプリとOracle CloudのAutonomous Databaseを接続する - アプリケーション環境編

Oracle Code Tokyoでハンズオンのお手伝いをしてきました!
ハンズオンは、Rails / laravel / Django / Spring Bootの4つのフレームワークを利用して、Oracle CloudのAutonomous Transaction Processingサービス(Oracle 18c)へ接続するサンプルアプリと、その手順を作っています。
私はSpring Boot(JPAを利用)のサンプルアプリとハンズオン手順、また、それに合わせてアプリの検証環境構築用のTerraformも作りました。

ハンズオンの手順やアプリはこちらのGitHubリポジトリに置いています。
ハンズオン手順と内容がかぶるところも多いのですが、この機会に、環境の作り方やデータベース接続方法などを整理したいと思います。

github.com

今回は、アプリケーション環境の設定手順を書いていこうと思います。
構成や環境構築編の内容についてはこちらです。
Spring BootのアプリとOracle CloudのAutonomous Databaseを接続する - 環境構築編 - そこに仁義はあるのか(仮)

f:id:syobochim:20190520002319p:plain

  • 👌 アプリで使っているもの
  • 👌 実行環境の設定
  • 👌 ビルド環境の設定
    • 1. ライセンス確認
    • 2. Mavenのsettings.xmlに認証情報を記載
  • 👌 テーブルの作成
続きを読む

Spring BootのアプリとOracle CloudのAutonomous Databaseを接続する - 環境構築編

Oracle Code Tokyoでハンズオンのお手伝いをしてきました!
ハンズオンは、Rails / laravel / Django / Spring Bootの4つのフレームワークを利用して、Oracle CloudのAutonomous Transaction Processingサービス(Oracle 18c)へ接続するサンプルアプリと、その手順を作っています。
私はSpring Boot(JPAを利用)のサンプルアプリとハンズオン手順、また、それに合わせてアプリの検証環境構築用のTerraformも作りました。

ハンズオンの手順やアプリはこちらのGitHubリポジトリに置いています。
ハンズオン手順と内容がかぶるところも多いのですが、この機会に、環境の作り方やデータベース接続方法などを整理したいと思います。

github.com

今回は、環境構築までの手順を書いていこうと思います。
アプリケーションの動作環境の設定についてはこちら。
syobochim.hatenablog.com

  • 👌 クラウド環境の構築
    • 手動で作成する場合
    • Terraformを使って作成する場合
  • 👌 仮想マシンの環境構築について
    • ビルド環境+実行環境
    • 実行環境
続きを読む

GETのクエリパラメータの値をオブジェクト変換してvalidationをかけるときのやりかた(spring-boot)

メモだよ

✏️ パラメータ受け取り

RequestParamでクエリパラメータを取れる。他の取り方もある!
Spring Boot 使い方メモ - Qiita

@GetMapping(value = "/")
@ResponseBody
String getType(@RequestParam Map<String, String> queryParameters) {
    ....
}

✏️ Objectに変換する

ObjectMapperをつかってmapからObjectにする
クエリパラメータがsnake caseでくる場合は、ObjectMapperに設定を追加する

XXForm form = new ObjectMapper().convertValue(queryParameters, XXXForm.class);

XXForm form = new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE).convertValue(queryParameters, XXXForm.class);

✏️ validationを実行する

Formにバリデーションを定義して、Validation実行。
精査に問題があったときは、violationsにエラー情報が設定される。

public class XXXForm {
    @NotNull
    public String type;
}
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<Object>> violations = validator.validate(form);
if (!violations.isEmpty()) {
    // バリデーションエラーのときの処理
}

✏️ 全体はこんな感じ

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.*;
import java.util.Map;
import java.util.Set;

@Controller
public class AuthenticationController {

    @GetMapping(value = "/")
    @ResponseBody
    String getType(@RequestParam Map<String, String> queryParameters) {
        XXForm form = getObjectMapper().convertValue(queryParameters, XXXForm.class);
        validate(authorize);
        // 正常処理
        return ...
    }

    private ObjectMapper getObjectMapper() {
        return new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    }

    private void validate(Object form) {
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(form);
        if (!violations.isEmpty()) {
            // バリデーションエラーのときの処理
        }
    }

}
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;

public class XXXForm {
    @NotNull
    public String type;

    public String state;

    @AssertTrue
    public boolean isType() {
        return responseType.equals("hogehoge");
    }
}

💭 うーーーーん

validationのときに、この値はこういうものだよ!って細かく定義したいけど、それって@AssertTrue使うのかな…?
相関ってわけじゃないので、モヤモヤする〜〜〜。
やりたいこととしては、そもそものプロパティのドメインって感じなんだけどな〜〜〜。

BeanValidationの相関バリデーションとそもそもの話 — 裏紙

上の記事がまさにソレ~!で、ドメインとして定義したい…

初心者大歓迎! webアプリを作ってみよう!勉強会のレポ起因にブログ書いてもらったからやってみた!!!

勉強会レポはこの記事
初心者大歓迎! webアプリを作ってみよう!勉強会に参加してSpring Bootさわってきた!!@ビズリーチ - そこに仁義はあるのか(仮)


で、追加で試してみたのはこの記事!!!
Spring Bootをやってみた — 裏紙
Spring BootのサンプルをGradle化した、けども…… — 裏紙
SpringBoot+Gradleでホットデプロイを使えるように - しおしお(´・ω・`)

続きを読む

初心者大歓迎! webアプリを作ってみよう!勉強会に参加してSpring Bootさわってきた!!@ビズリーチ

勉強会でビズリーチに行ってきたよ!

オフィス、芝生あるし海あるし、波の音するし、さえずり聞こえるし最高だった。
ちなみに、勉強会の内容は、SpringBootJavaで、twitterみたいなwebアプリを作ろう!って感じだったよ!

twitter廃人的に、ハッシュタグ欲しかった><

続きを読む