🐇

Dress Code QAチーム立ち上げの軌跡(2025年振り返り)

に公開

はじめに

Dress Code Advent Calendar 2025 の 9 日目の記事です。
Dress Code は創業1年目の会社で、コンパウンドプロダクト「DRESS CODE」の提供を通して企業の経営や業務で発生するあらゆる摩擦問題を解消することを目指しています。
いわゆる「2周目人材」つまり「猛者中の猛者」たちが集い、圧倒的分量・圧倒的スピードで様々な価値や機能を世の中に提供しています。
Dress Code が何なのか?何をしたいのか?などなどの詳細については公式のCEOインタビューで詳しく紹介されているため、前提理解にあたり一読をおすすめします!
https://note.com/dresscode/n/n5a808cbf3d46

この記事の概要

概要をさくっと確認用に、Google Nano Banana Pro に概要をまとめてもらいました。

自己紹介

業務委託としてQAマネージャーを担当している、うさぴょんです!
私の普段の活動は、いくつかのお客様に対して、QAチームの営みを作り、見守り支えるというようなマネージャー的なことから、テスト実行やレポートも行いつつ、昨今のAIの流れから技術調査・導入まで行う、いわゆる全部やる系のプレマネみたいなことをやっています。

QAチーム立ち上げ

アドカレのネタを考える中で、やっぱり今年1年の振り返りかなぁ何にしようかなぁと、何をしてきたかを振り返ってみたところ、Dress Code でQAチームの立ち上げとその支援をしてきたことは大きいなと感じました。
創業初期の頃から関わらせていただいておりますが、創業時点から品質部隊まで用意する(というかできる)のは、会社としてすごいことです。

さて、ではQAチームとして何もない状態から、さぁどうぞ!やっちゃってください!となった時に、何をしてきたか・考えてきたかを振り返りを含めつつ記載してみます。
これからQAチームを立ち上げようと思っている方や、QAチームが何を思っているか知りたい方などの何かに刺されば幸いです。(具体的なところはぼかしたり書かなかったりしています。ご留意ください。)

テストを作る

リリースの箱自体は存在している状態でしたので、リリース対象からどういうテストをすべきかを考えました。
「すべき」というのは、「時間と品質のバランスを見極めるための、絶妙なラインを攻める」に近い感覚です。
どういうことかというと、状況として

  • 早く出さないといけない
  • すぐ使えないといけない

というフェーズにおいて、リッチすぎるテストをしようとしたところで時間がかかりすぎて間に合いませんし、やったとしてもその結果のレポートははっきり言って邪魔なだけです。今そこじゃないんだよね、ってなりがちです。
なので、「今回、このシナリオは絶対に譲れない」「今回提供したい価値はこれ」というような死守ラインを定義しテストケースに落とし込み、あとはその周辺と機能的な観点(いわゆるCRUD)は落とさない方針にしようと決めます。

また、新機能がバンバン出る状況だと情報の追従が間に合ってなくて「これ何?」が連発するのですが、普通に「これ何?」をやります。優先度が日々変わったりする中だと、昨日の情報がもう古すぎるということはよくあるので、拾いにいくスタンスも必要です。

テストする

2025年はAIの進化がますます加速していて、開発生産量も鬼のように増えていくのを目の当たりにしていました。コードを書く段階からテスト視点で提案してくれたり、逆にテストから得たフィードバックをAIが修正したり。なので今後、この作業は開発、この作業はQAって明確に分けられなくなってくると感じています。

しかしそうは言っても、目の前のテストをやる必要がある!それもかなりの分量があるよね!となった時に、以下の技術が重宝しました。
ポイントとしては、従来のようなコーディングなどにおける技術的な敷居が比較的低い点と、設計資料・インプットからほぼそのまま形にできるところが良さそうだったので採用しました。

Playwright MCP

Cursor と組み合わせて使用しており、自然言語だけでテスト実行・レポートまでやってくれます。
主に、以下の点で効果的だと感じており、もうこれなしの生活には戻れません(笑)

  • 探索的テスト

テスト環境にリリースが適用された後、そもそもちゃんと狙い通りのものが入っているかしら?という視点でささっと見たい時があります。
そして、テスト環境にリリースが適用されたタイミングで、都合よく手が動かせない時もあります(ミーティング中だったり、移動中だったり・・・)
なので、事前に「見たいポイント」を文章化しておき、テスト環境の準備が整ったらそれを実行するようにしています。

  • リグレッションテスト

リリースのテストとしては終盤になりますが、今まで使えてた機能が意図せず使えなくなってないことを確認します。
機能が増えるごとに確認対象が増えるため、リグレッションテストの工数沼にはまってしまうと、最終的には「リリースするまでの儀式、長いなぁ」という感覚を持たせてしまいます。費用対効果もよくわからなくなってしまいがちです。
Playwright MCP の使い所としては、「ここは破壊的な変更がしばらく入らないところ」のアタリをつけた上で、定型的なテストケースはすべて文章化しました。

具体的なシーンの例として、DRESS CODE ではSaaS連携機能があり、SaaSとのアカウント連携が可能なのですが、画面としては大きな変更はまだ入らない想定ということもあり、ここを対象にテストを組みました。
以下のようなファイルを用意します。

SaaS認証情報ファイル
ここにはSaaSと接続するための情報が記載されているというテイ
SaaSテスト対象ファイル
ここにはテスト対象とするSaaSの名称が記載されているというテイ

連携SaaSが増える場合を考えて、上記のテスト対象ファイルと認証情報ファイルを追記すればいいようにしておきます。

テスト環境情報ファイル
ここにはDRESS CODEのURLやユーザー情報が記載されているというテイ
テスト方針ファイル
# 基本方針
・cursorに設定されている Playwright MCP を利用してテストしてください。
・テスト対象のURLなどの環境情報は環境情報フォルダに配置されている環境情報設定ファイルを参照します。
・テストケースはテストケースフォルダにファイルが配置されています。テストシナリオを上から順番に、記載されている通りすべてをテストします。
・テスト対象のアプリはテスト対象ファイルに記載されています。
・テスト対象のアプリの認証情報は認証情報フォルダ以下に配置されています。テスト対象となっていないアプリは、テストを実行しません。
・テストがNGとなる場合、エラーが発生している場合は、エラーの内容も記録します。

# テスト完了レポート
・テストケースは数量がわかるように、先頭に数値のみで通し番号を付与します。
・テストが完了したら、テスト結果をOK or NGでレポートします。
・テスト結果は以下のファイル名規則で「csv形式」で保存してください。
CSVに出力する際、各テストケースは、通し番号を付与してください。1,2,3... のようにテストケースごとに、最初の列に通し番号を付与します。
ファイル名規則:tc01_テスト実行日時.csv(ミリ秒まで含める)
ただし、テストケースファイルを複数作る場合、tc01、tc02、tc03... と番号を増やしていきます。
例として、次のようなファイル名を期待します。
例:tc01_20250714_123000_456.csv
・テスト結果のcsvは、testresultフォルダに配置します。
テストケースファイル(一部抜粋)
・URLを開けること
・「ソフトウェア一覧」タブをクリックし、連携一覧画面が開けること
・「マーケットプレイス」タブをクリックし、マーケットプレイス画面が開けること
・検索ボックスからテスト対象ソフトウェアが検索できること
・表示されているテスト対象ソフトウェアをクリックすると、ソフトウェア登録画面が開くこと
・「利用可能な機能」に、アカウントについてのラベルが過不足なく表示されていること
・「連携する」ボタンをクリックすると、登録ダイアログが開くこと
・登録ダイアログに認証情報を設定し、「連携する」ボタンをクリックすると、ソフトウェア詳細画面に遷移すること
...

上記ファイルをコンテキストに、実行します。

プロンプトの例:
以下の要件でテストを実行してください:
1. テスト対象:テスト対象ファイルで定義されている全てのアプリ
2. テスト方針:基本方針ファイルの記載内容に従う
3. テスト実行:MCP tool(Playwright)を使用
4. 結果出力:CSVファイル形式
5. ファイル命名規則:各アプリごとに個別ファイルを作成
    - 例:tc01_アプリ名_YYYYMMDD_HHMMSS.csv
各アプリのテストが完了したら、全体のサマリーレポートも作成してください。

こうすると実行結果が CSV で出てくるのでレポートの元データがすぐできるのと、「そもそも通らない」みたいなものはサマリーで教えてくれるため、Criticalな事象にすぐ気づくことができます。

意図的に認証に異常値を設定し連携作成を失敗させた場合、以下のような出力になりました。

テスト結果サマリーの例
テスト結果サマリー
XXX のテストを実行しました。連携作成時にHTTP 403エラーが発生したため、要件に従いNGとして記録し、テストを中止しました。

テスト結果
総テストケース数: 8
OK: 7
NG: 1(連携作成の失敗)
成功率: 87.5%

生成されたファイル
詳細テスト結果: testresult/tc01_xxx_20201231_102030.csv
アプリ別サマリー: testresult/summary_xxx_20201231_102030.csv
全体サマリー: testresult/overall_summary_20201231_102030.csv

実行されたテストケース
✅ テスト環境URLを開く
✅ 「ソフトウェア一覧」タブをクリック
✅ 「マーケットプレイス」タブをクリック
✅ 検索ボックスでXXXを検索
✅ XXXのソフトウェア登録画面を開く
✅ 「利用可能な機能」のラベル表示を確認
✅ 「連携する」ボタンで登録ダイアログを開く
❌ 連携作成(HTTP 403エラーにより失敗)
連携作成が失敗したため、以降のテストは実行していません。
そもそも通らなかったパターンの結果CSVの例
1,URL を開けること,OK,
2,「ソフトウェア一覧」タブをクリックし、連携一覧画面が開けること,OK,
3,「マーケットプレイス」タブをクリックし、マーケットプレイス画面が開けること,OK,
4,検索ボックスからテスト対象ソフトウェアが検索できること,OK,
5,表示されているテスト対象ソフトウェアをクリックすると、ソフトウェア登録画面が開くこと,OK,
6,「利用可能な機能」に、アカウントについてのラベルが過不足なく表示されていること,OK,
7,「連携する」ボタンをクリックすると、登録ダイアログが開くこと,OK,
8,登録ダイアログに認証情報を設定し、「連携する」ボタンをクリックすると、ソフトウェア詳細画面に遷移すること,NG,HTTP 403エラー: Internal Server Error - 連携作成に失敗しました
  • テストデータの準備

代表的なものとして、現在 DRESS CODE では労務機能を提供しており、その中にはいくつもの手続きが存在します。
(入社手続き、業務契約手続き、復職・休職、住所変更手続き、など)
たとえば業務として「復職」をしようと思った場合、当たり前ではあるのですが入社している従業員がいて、復職の判断があってと、いくつかの業務を辿ったあとに行う必要があります。
これを毎回1から手で行っていくのはかなり時間がかかってしまいます。
なので、ある業務を行う前までの状態を作れるように、操作を自動化しました。
(裏からデータを投入すればいいのでは?というのもあるのですが、意図しない不整合データをうまない & リグレッション検知も兼ねて、表からやっています。)

runn

Dress Code では単体テスト・結合テストは開発者が書いているのですが、いわゆるE2Eテストにあたるレイヤは自動テストが不足しているのが課題でした。
API E2Eテストとして Jest / Supertest で書き始めていましたが、大ボリュームの機能郡が待ち構えていることからすぐに量産したい状況を想定したところ、多くのメンバーでも再現できるように「YAMLベースで、習熟度がそこまで高くないQAメンバーでも理解できるように」「設計・仕様ドキュメントからすぐにテストが書けそう」という理由で、runn を採用しました。(あと、個人的に新しい技術に触れたいというのもありました。)

runn のリポジトリはこちら
https://github.com/k1LoW/runn

runn のチュートリアルはこちら
https://zenn.dev/katzumi/books/runn-tutorial

CRUDやライフサイクル、ハッピーパスを一発通したいのと、テスト期間中は日々自動テストを回してデグレチェックを行うという用途で使っています。
たとえば以下です。

XXXのハッピーパス.yml
desc: XXXのハッピーパス 

vars:
  auth_token: ${RUNN_AUTH_TOKEN:-YOUR_AUTH_TOKEN}

runners:
  req:
    endpoint: ${RUNN_BASE_URL:-http://localhost:3000}

steps:
  - desc: テストデータ用のユニークIDを生成
    bind:
      uuid_suffix: faker.UUID()

  - desc: 1. 作成 POST /v2/XXX 全項目検証
    include:
      path: steps/post-xxx.yml
      vars:
        auth_token: '{{ vars.auth_token }}'
        request_body: json://../payloads/xxx.json.template
    bind:
      xxx_id: current.xxx_id
      xxx_name: current.xxx_name

  - desc: 2. 一覧取得 GET /v2/xxx
    req:
	    /v2/xxx
      get:
        headers:
          Accept: application/json
          Authorization: '{{ vars.auth_token }}'
        query:
          page: 1
          pageSize: 20
          orderBy: 'createdAt'
          orderDirection: 'DESC'
	  test: current.res.status == 200
      && len(current.res.body.items) == 1
      && current.res.body.items[0].xxxName == xxx_name

finally:
  - desc: 削除 DELETE /v2/xxx/:id (cleanup)
    req:
      /v2/xxx/{{ xxx_id }}:
        delete:
          headers:
            Authorization: '{{ vars.auth_token }}'

切り出して共通的に使えるようにすることもできます。
以下はPOSTのステップを共通部品として切り出しました。

XXX作成.yml
desc: xxx作成 POST /v2/xxx (component)

steps:
  - desc: POST /v2/xxx (component)
    req:
      /v2/xxx:
        post:
          headers:
            Content-Type: application/json
            Authorization: '{{ vars.auth_token }}'
          body:
            application/json: '{{ vars.request_body }}'
    test: current.res.status == 201
    bind:
      xxx_id: current.res.body.id
      xxx_name: current.res.body.xxxName

テストデータも json.template として切り出せます。

xxx.json.template
{
  "xxxName": "{{ if .xxx_name }}{{ .xxx_name }}{{ else }}{{ printf "test-%s" .uuid_suffix }}{{ end }}",
...

runn は yaml で振る舞い等のドキュメントを記述するかのようにシナリオを書けるので、直感的で勝手にシンプルになっていくのが嬉しいです。
複雑なビジネスロジックに対応したり細かい制御もできるはずですが、そうなると冗長になったりメンテナンスしにくかったりしそうなので、データ中心に制御できるようにもっていきたいところです。

テストレポート

テストによって検知した不具合や課題は、QA指摘としてデータにします。
不具合のインパクトから重み付けを行い、「これはすぐ直さないといけない」「これはいついつに直す」など判断が必要です。
その時にすぐ直せるものはいいのですが、「重めの課題だけど、まとめて直したい」「この時点ではすぐ使わない」などもあり、バックログが肥大化していくことが課題になりました。
バックログにアイテムが溜まっていくと、その中でも優先度付が難しくなるため、なぜバックログにしたのかをわかるようにコメントとラベル付けを行います。
ラベルの例は以下のようなものです。

検知範囲

分類 意味合い
リリース対象 そのリリースに影響がある
リリース対象の周辺 そのリリースに本質的には影響がない

リリース対象の場合は、優先度高く見る必要があります。
一方でリリース対象の周辺は、そのリリースにおいては直接的な価値の毀損にはならないが検知できた課題、として定義しました。
さらに、バックログにした理由としては以下です。

要因分類

分類 理由
内的要因 今回対応しきれなかった
潜在不具合
仕様検討不足
共通部分の問題
エッジケース
その他
外的要因 再現性が低い
他機能の開発待ち
別対応へ切り替えた

内的要因に関してはリスクが高いため、計画的に対応できるように管理を行っていくことが必要です。
また、潜在的に起こる課題は潜在だからという理由で後回しにするのではなく、当該リリースで見た時に対応すべきかを判断することが重要です。

リリース判定

最初に打ち立てた、テスト軸でのリリース判定は以下のようなものでした。

  • 用意されているテストがすべて実行されているか。
  • リリースの責任者がテスト結果をレビュー済みか。
  • 当リリースのテストで検知した不具合が、以下条件にあてはまること。
    • Critical 以上の残存不具合が 0 であること。
    • Major の残存不具合を許容する場合、ユーザーに対する対応が決まっていること。
    • Normal 以下の残存不具合のうち、今回リリースで修正すべき不具合が残っていないこと。
  • ステークホルダー間で合意済みであること。

Critical / Major / Normal といった指標は、テストで見つかった不具合に対して「不具合重要度」としてランク付けしているものとなります。
しかし、開発やテストが終わり切らずに、リリース日を直前に検討し直す課題がありました。
これは、リリース日までに開発やテストが終わるのかどうか、進捗が見えにくいことに起因しています。
打開策としては、少なくともリリース前日にリリース判定を行うことを前提に、基準を加えました。

  • テスト進捗が XXX %を超えていること
    • さらに、テスト実行にかかる時間が YYY 未満であること(≒現実的に、開発とテストを対応できる時間)
  • Major 以上の残存不具合数が N 件未満であること

まだ始めたばかりの施策ですが、リリースに対して「Go」or「No Go」を客観的に出せる指標として、解像度が高まりました。

おわりに

2025年を振り返って、Dress Codeというスタートアップの熱量の中でQAチームを立ち上げ、走りながら考え、そして作り上げていったこの経験は、間違いなく私のキャリアの中でも特別なものになりました。
プロダクトの成長スピードに負けないように、品質も同じ熱量で支える。まだまだ理想には遠いかもしれませんが、それでも一歩ずつ形になっていく過程を楽しみながら進められたと思っています。
もし、この記事がこれからQAチームを立ち上げようとしている方、またはスタートアップにおけるQAの役割を模索している方の参考になれば、とても嬉しいです。

DRESS CODE TECH BLOG

Discussion