こちらの記事は NewsPicks Advent Calendar 2024 の3日目の記事です。
はじめに
こんにちは、ニューズピックスでQAエンジニアをやっています西薗です。最近まで育休をとっていたこともあって、ここ1年くらいブログを書いたり登壇したりといったことをしておらず、もともと知られてないのにさらに業界から忘れられていっているのでは感が出ています。次男ももうすぐ1歳になるので、また頑張ります。
我々にはデータベースが必要だ
普段の業務で、データベースとフロントを持つアプリケーションを作りたい、と思うことが結構あります。開発エンジニアとして成長したい!とかそういう話ではなく、実需の話です。
例えば私は最近、APIの一覧とテストコードがあって、その紐付けをデータベースに格納し、APIのカテゴリごとにテストカバレッジをユーザーに見せるようなアプリケーションが欲しいな、と思いました。スプレッドシートでも管理はできるんですが、カテゴリごとに表示したり、そこからテストコードに飛ばしたり、って色々考え出すと逆に面倒なんですよね。
それこそ、データベースを用意して、そこにフロントを作るか、という話になってしまう。データベースはSQLite
にして、フロントは……ってことを私がやりだすとテストケースの更新などが疎かになりそうなので、さくっとやりたい。
Notion とは
私の理解では、Wikiというフロントを持ったデータベースです。複数のテーブルを定義でき、各レコードはwikiページとして編集が可能。また全てのページどころか、ページ内の全ての要素にいたるまでが個別のURLを持ちます。
自動化の機能も豊富で、後述するAPIを使う方法を含め、いろんな外部ツールとも連携が可能。いまどきの、多種多様なSaaS製品を使う職場環境とよくマッチしたのでしょう、ここ数年で一気に利用が広がったようです。
私も、大抵の用事はNotionで出来ちゃう、と思い始めました。これは令和のエクセルですよ。私が勝手にそう呼んでるだけですが。
ということで Notion を使おう
色々できちゃうNotionですが、あくまでGUIのドキュメンテーションツールです。画面左端にツリー構造があって、そのうちの一つを開くとWikiページが表示されて、ページの中で新たなテーブル定義を作ったり(データベースの作成)、そこにレコードを挿入したり(ページの挿入)、レコードを開くとまたWikiページが表示されたりします(レコード=ページなので、それもまたWikiページとして編集が可能)。
これまでのWiki系製品と比べると十分に自由度が高くて便利だなと思います1が、これを「システム」として使うとなると、レコードの挿入や削除、変更といった操作はプログラムから行いたいですね。
Notion API を使う
Notion は利用者に API を公開してくれておりまして、これを使うとデータベースの定義やレコードの挿入、更新などがHTTPメッセージを投げることで行えます。JavaScriptからNotion APIを叩くためのライブラリも公開されています。
実装
ここからは、先述したAPIテストのカバレッジを見るためのシステムをさらっとご紹介します。
カバレッジの取得方法を決める
NewsPicks Server は Swagger(OpenAPI) 対応しており、開発環境であれば API のエンドポイント一覧が取得できます。またAPIテストは @openapitools/openapi-generator-cli で生成した API Client を使って実装をしていますから、以下の関係を引っ張ってくればカバレッジを計測できそうです。
API endpoint の一覧 -(1)-> API Client のメソッド -(2)-> テストコード内でのメソッド呼び出し
(1) API endpoint の一覧 -> API Client のメソッド
openapi3.json
から、jq
を使って欲しい情報を抽出します。具体的には、paths
直下のキー名がエンドポイントで、その下にキー名としてHTTPメソッド(get
なのかpost
なのか)があり、その中の operationId
が API Client のメソッド名として使われます。
{
"openapi": "3.0.0",
"paths": {
"/path/to/endpoint": {
"get": {
"tags": [
"qa-controller"
],
"summary": "JavaMethod: QAController/getTestCase",
"operationId": "getTestCaseUsingGET",
例えばoperationId
ならこんな感じで抽出ができますね。この要領で必要な情報をCSVなどに落とします。
cat ../openapi3.json | jq -r '..|.operationId?|strings'
(2) API Client のメソッド -> テストコード内でのメソッド呼び出し
本当はASTなど使えば良いのでしょうが、さくっとやりたかったので、テストコード内でそのメソッドが呼び出されているか否かは文字列を検索することで確認します(従って、コメントアウトなどは考慮しません)。以下、シェルスクリプトの抜粋です。
# ${METHOD}がテストコードに含まれていることを確認する
ISCOVERED=$(grep -ro "${METHOD}\W" "${PR_HOME}/../src/test" | wc -l | tr -d ' ')
if [[ $ISCOVERED -gt 0 ]]; then
ISCOVERED="TRUE"
else
ISCOVERED="FALSE"
fi
(3) API一覧と、テストコードで呼び出されているか否かを Notion DB に書き込む
なんだかんだあってAPI名と、それがテストコードで呼び出されているかがズラッと書かれたCSVファイルが出来上がりまして、今度はそれを Notion API を使って Notion に書き込みます。
controller,apiEndpoint,apiTestMethod,isCovered
qa-controller,get /path/to/endpoint,getTestCaseUsingGET,TRUE
qa-controller,post /path/to/endpoint,createTestCaseUsingPOST,FALSE
Notion 側で予め、API一覧と、それがテストでカバーされているかという情報を格納するデータベースを用意します。
型定義っぽく書くならこんな感じ(こちらはあくまで擬似コードですが)。
const APIs = {
"apiEndpoint": TITLE,
"controller": RICH_TEXT,
"apiTestMethod": RICH_TEXT,
"isCovered": CHECKBOX,
}
そして、これをNotion APIで送信します。下記コードではわかりやすいように値を直接入れてます。
await client.pages.create({
parent: {
database_id: "<データベースのIDを記載>",
type: "database_id",
},
properties: {
"apiEndpoint": { title: [{ text: { content: "get /path/to/endpoint" } }] },
"controller": { rich_text: [{ text: { content: "qa-controller" } }] },
"apiTestMethod": { rich_text: [{ text: { content: "getTestCaseUsingGET" } }] },
"isCovered": { checkbox: true },
},
});
と、こんな感じで初めましてのSDKを使って試行錯誤した結果、何となく格好がつきました。下図では2レコードですが、実際にはスクロールするのも大変な量のレコードがあります。これが勝手に入ってくれると気持ちいいですね。
ちなみにカバレッジ(一番左の50%
がそれです)を計算する都合上、レコードの親子関係と、Rollup propertyというものを使っています。子レコードの特定のプロパティ(isCovered
)を一通りみて、true
になっているレコードの割合を計算することでカバレッジを算出しました。このあたりはGUIの設定だけで実現可能です。
(4) 以上の仕組みをGitHub Actionsで呼び出す
もう一つやったことがありました。ここまでお話しした仕組みを手で動かすのではなく、GitHub Actionsに組み込みました。こちらはymlファイルですね。
リポジトリのテストフォルダ以下が編集され、mainブランチにマジされたら勝手に動いてくれます。
on:
push:
branches:
- main
paths:
- 'test/api/**'
jobs:
<略>
おわりに
今回はとにかく「Notionいいよ!」ということを伝えたかったのと、「QAエンジニアのみんな、Notion使えば少しの開発でもそれっぽいものが出来るからぜひやってみてね!」ということが言いたかったのでした。一旦さらっとご紹介、というところで。
今回紹介した仕組みについては、もうちょっとその周辺でやっていることがあるので、別途また紹介しようかなと思います。
-
ということをQiitaで書くなよ、と後から思いましたが、Notionでブログを書きたいかというとまた違うんですよね。 ↩