0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

rex0220 アプリマイスター・レイ テストデータの生成

Last updated at Posted at 2025-11-27

rex0220 アプリマイスター・レイで、kintone アプリのテストデータを生成してみます。

概要

アプリを作成してプラグインのテストを行う場合、まとまった数のテストデータが必要です。
rex0220 アプリマイスター・レイで、顧客アプリを作成して、テストデータを1,000件生成してみます。

  • 作成した顧客マスタとテストデータ

2025-11-27_10h55_20.png

作成手順

  • 顧客マスタ作成
  • テストデータ生成
    • 生成されたテストデータを見ると、顧客名の重複が多い
    • 再調整を繰り返し

顧客マスタ作成

顧客マスタアプリを作成
・顧客コード: "A0001", "A0002", ...
・顧客名: "織田信長", "徳川 家康", ...
・顧客ランク: ドロップダウン "A","B","C"
他に顧客マスタに必要な項目を追加

2025-11-27_11h00_20.png

/**
 * 🦊 kintone App Meister Ray's Work
 * Project: 顧客マスタ構築
 */
(async () => {
  try {
    console.log('🦊 レイ: 顧客マスタアプリの構築を開始します!');

    // -------------------------------------------------------
    // 1. 新規アプリの作成(プレビュー)
    // -------------------------------------------------------
    const createAppBody = { name: '顧客マスタ' };
    const createResp = await kintone.api(kintone.api.url('/k/v1/preview/app', true), 'POST', createAppBody);
    const appId = createResp.app;

    console.log(`Step 1: アプリの枠を作成しました... App ID: ${appId}`);

    // -------------------------------------------------------
    // 2. フィールドの追加
    // -------------------------------------------------------
    const fieldsBody = {
      app: appId,
      properties: {
        // --- 基本情報 ---
        '顧客コード': {
          type: 'SINGLE_LINE_TEXT',
          label: '顧客コード',
          code: '顧客コード',
          unique: true,      // 重複禁止
          required: true,    // 必須
          minLength: '1'
        },
        '顧客名': {
          type: 'SINGLE_LINE_TEXT',
          label: '顧客名',
          code: '顧客名',
          required: true
        },
        '顧客ランク': {
          type: 'DROP_DOWN',
          label: '顧客ランク',
          code: '顧客ランク',
          options: {
            'A': { label: 'A', index: 0 },
            'B': { label: 'B', index: 1 },
            'C': { label: 'C', index: 2 }
          },
          defaultValue: 'C',
          required: true
        },

        // --- 連絡先・所在地情報(あると便利な項目を追加しました!) ---
        '郵便番号': {
          type: 'SINGLE_LINE_TEXT',
          label: '郵便番号',
          code: '郵便番号',
          maxLength: '8'
        },
        '住所': {
          type: 'SINGLE_LINE_TEXT',
          label: '住所',
          code: '住所'
        },
        '電話番号': {
          type: 'LINK',
          label: '電話番号',
          code: '電話番号',
          protocol: 'CALL'
        },
        'メールアドレス': {
          type: 'LINK',
          label: 'メールアドレス',
          code: 'メールアドレス',
          protocol: 'MAIL'
        },
        '担当者名': {
          type: 'SINGLE_LINE_TEXT',
          label: '担当者名',
          code: '担当者名'
        },
        
        // --- 管理情報 ---
        '締め日': {
            type: 'DROP_DOWN',
            label: '締め日',
            code: '締め日',
            options: {
                '末日': { label: '末日', index: 0 },
                '20日': { label: '20日', index: 1 },
                '10日': { label: '10日', index: 2 },
                'その他': { label: 'その他', index: 3 }
            },
            defaultValue: '末日'
        }
      }
    };

    await kintone.api(kintone.api.url('/k/v1/preview/app/form/fields', true), 'POST', fieldsBody);
    console.log('Step 2: フィールド設定完了。連絡先情報も追加しておきました!');

    // -------------------------------------------------------
    // 3. アプリのレイアウト設定
    // -------------------------------------------------------
    const layoutBody = {
      app: appId,
      layout: [
        {
          type: 'ROW',
          fields: [
            { type: 'SINGLE_LINE_TEXT', code: '顧客コード', size: { width: 200 } },
            { type: 'SINGLE_LINE_TEXT', code: '顧客名', size: { width: 300 } },
            { type: 'DROP_DOWN', code: '顧客ランク', size: { width: 150 } }
          ]
        },
        { type: 'ROW', fields: [{ type: 'HR', size: { width: 600 } }] }, // 区切り線
        { type: 'ROW', fields: [{ type: 'LABEL', label: '▼ 所在地・連絡先' }] },
        {
          type: 'ROW',
          fields: [
            { type: 'SINGLE_LINE_TEXT', code: '郵便番号', size: { width: 150 } },
            { type: 'SINGLE_LINE_TEXT', code: '住所', size: { width: 400 } }
          ]
        },
        {
          type: 'ROW',
          fields: [
            { type: 'LINK', code: '電話番号' },
            { type: 'LINK', code: 'メールアドレス' }
          ]
        },
        {
            type: 'ROW',
            fields: [
              { type: 'SINGLE_LINE_TEXT', code: '担当者名' },
              { type: 'DROP_DOWN', code: '締め日' }
            ]
        }
      ]
    };

    await kintone.api(kintone.api.url('/k/v1/preview/app/form/layout', true), 'PUT', layoutBody);
    console.log('Step 3: レイアウト設定完了');

    // -------------------------------------------------------
    // 4. 一覧設定
    // -------------------------------------------------------
    const viewsBody = {
        app: appId,
        views: {
            '一覧': {
                type: 'LIST',
                name: '一覧',
                index: 0,
                filterCond: '', 
                sort: '顧客コード asc',
                fields: ['顧客コード', '顧客ランク', '顧客名', '電話番号', '担当者名']
            }
        }
    };

    await kintone.api(kintone.api.url('/k/v1/preview/app/views', true), 'PUT', viewsBody);
    console.log('Step 4: 一覧設定完了');

    // -------------------------------------------------------
    // 5. アプリの公開 (Deploy)
    // -------------------------------------------------------
    console.log('Step 5: アプリの公開処理を実行中...');
    await kintone.api(kintone.api.url('/k/v1/preview/app/deploy', true), 'POST', { apps: [{ app: appId }] });

    // -------------------------------------------------------
    // 完了メッセージ
    // -------------------------------------------------------
    console.log('-------------------------------------------------------');
    console.log(`🎉 レイ: 作成完了です!`);
    console.log(`新規作成されたアプリID: ${appId}`);
    console.log('作成されたアプリを開いて、レイアウトを確認してみてください。');
    console.log('-------------------------------------------------------');

  } catch (error) {
    console.error('🦊 レイ: おっと、エラーが発生しました。一緒に確認しましょう。', error);
    if (error.error) console.error(JSON.stringify(error.error, null, 2));
  }
})();

テストデータ生成コード

最終的に重複のないテストデータ生成コード

/**
 * 🦊 kintone App Meister Ray's Work
 * Project: 顧客マスタ テストデータ生成 (完全ユニーク版)
 * Description: 同姓同名が一切ない1000件のデータを生成します
 */
(async () => {
  const appId = kintone.app.getId();
  if (!appId) {
    console.error('🦊 レイ: アプリの画面を開いてから実行してください!');
    return;
  }

  console.log(`🦊 レイ: アプリ(ID: ${appId}) に、名前の重複がない1000件を生成します...`);

  // --- 1. データ生成用の素材 ---
  const lastNames = [
    "佐藤", "鈴木", "高橋", "田中", "伊藤", "渡辺", "山本", "中村", "小林", "加藤",
    "吉田", "山田", "佐々木", "山口", "松本", "井上", "木村", "", "斎藤", "清水",
    "山崎", "", "池田", "橋本", "阿部", "石川", "山下", "中島", "石井", "小川",
    "前田", "岡田", "長谷川", "藤田", "後藤", "近藤", "村上", "遠藤", "青木", "坂本",
    "斉藤", "福田", "太田", "西村", "藤井", "金子", "和田", "中山", "三浦", "吉野",
    "荒木", "上田", "小野", "菊地", "佐野", "柴田", "菅原", "高木", "千葉", "中川",
    "西田", "野口", "馬場", "平野", "藤本", "松田", "水野", "安田", "山内", "横山",
    "芦田", "新井", "岩田", "内田", "大島", "大野", "岡本", "片山", "川口", "北村",
    "工藤", "久保", "古賀", "小島", "酒井", "桜井", "沢田", "島田", "杉山", "高田",
    "武田", "谷口", "", "中野", "野村", "服部", "", "原田", "樋口", "星野"
  ];

  const firstNames = [
    "翔太", "大輔", "健太", "", "直樹", "達也", "", "拓哉", "亮太", "一平",
    "陽菜", "", "美咲", "知花", "結衣", "美優", "七海", "里奈", "花子", "未来",
    "", "大和", "", "陽翔", "悠真", "結菜", "莉子", "芽依", "咲良", "",
    "一郎", "次郎", "三郎", "四郎", "五郎", "信長", "秀吉", "家康", "政宗", "幸村",
    "浩一", "健一", "次郎", "三郎", "四郎", "賢二", "修平", "大樹", "達郎", "哲也",
    "直人", "秀樹", "", "", "", "", "", "康夫", "雄大", "洋介",
    "", "香織", "加奈", "久美子", "早紀", "里美", "志帆", "朋子", "直美", "奈緒",
    "晴香", "", "麻衣", "真由美", "美香", "", "由佳", "洋子", "理恵", "玲奈",
    "", "", "", "", "朝陽", "日向", "奏太", "伊織", "", "瑛太"
  ];

  const ranks = ["A", "B", "C"];
  const closings = ["末日", "20日", "10日", "その他"];
  const prefectures = [
    "北海道", "青森県", "岩手県", "宮城県", "秋田県", "山形県", "福島県",
    "茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都", "神奈川県",
    "新潟県", "富山県", "石川県", "福井県", "山梨県", "長野県", "岐阜県",
    "静岡県", "愛知県", "三重県", "滋賀県", "京都府", "大阪府", "兵庫県",
    "奈良県", "和歌山県", "鳥取県", "島根県", "岡山県", "広島県", "山口県",
    "徳島県", "香川県", "愛媛県", "高知県", "福岡県", "佐賀県", "長崎県",
    "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"
  ];

  const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
  const randNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

  // --- 2. 重複なしで1000件のデータを作成 ---
  const records = [];
  const generatedNames = new Set(); // 生成済み名前管理用
  let counter = 1;

  // recordsが1000件になるまで繰り返す
  while (records.length < 1000) {
    const ln = pick(lastNames);
    const fn = pick(firstNames);
    const fullName = `${ln} ${fn}`;

    // 既に生成した名前ならスキップして再抽選
    if (generatedNames.has(fullName)) {
      continue;
    }
    
    // 新しい名前なら採用して記録
    generatedNames.add(fullName);

    // 担当者名(こちらは重複してもOKとする)
    const managerName = `${pick(lastNames)} ${pick(firstNames)}`;
    const tel = `090-${String(randNum(0, 9999)).padStart(4, '0')}-${String(randNum(0, 9999)).padStart(4, '0')}`;
    const pref = pick(prefectures);
    const city = ["北区", "南区", "中央区", "港区", "新宿区", "渋谷区", "青葉区"][randNum(0, 6)];

    records.push({
      '顧客コード': { value: `CUST-${String(counter).padStart(5, '0')}` },
      '顧客名': { value: fullName },
      '顧客ランク': { value: pick(ranks) },
      '郵便番号': { value: `${randNum(100, 999)}-${randNum(1000, 9999)}` },
      '住所': { value: `${pref}${city} ${randNum(1, 9)}丁目${randNum(1, 20)}-${randNum(1, 20)}` },
      '電話番号': { value: tel },
      'メールアドレス': { value: `user${counter}@example.com` },
      '担当者名': { value: managerName },
      '締め日': { value: pick(closings) }
    });
    
    counter++;
  }

  console.log('Step 1: ユニークデータ生成完了。サーバーへの送信準備中...');

  // --- 3. 100件ずつ分割して登録 ---
  try {
    const chunkSize = 100;
    for (let i = 0; i < records.length; i += chunkSize) {
      const chunk = records.slice(i, i + chunkSize);
      
      const body = {
        app: appId,
        records: chunk
      };

      await kintone.api(kintone.api.url('/k/v1/records', true), 'POST', body);
      console.log(`... ${Math.min(i + chunkSize, records.length)} / 1000 件 登録完了`);
    }

    console.log('-------------------------------------------------------');
    console.log('🎉 レイ: 完了しました!');
    console.log('1000件すべて異なる名前の顧客データが登録されました。');
    console.log('-------------------------------------------------------');

  } catch (error) {
    console.error('🦊 レイ: エラーが発生しました。', error);
    if (error.error) console.error(JSON.stringify(error.error, null, 2));
  }
})();
  • テストデータ生成結果

2025-11-27_10h48_56.png

テストデータ生成作成手順

テストデータを生成して、問題を対策しながら調整していきます。

テストデータ生成1

最初はざっくりとした要件で

顧客マスタにテストデータ1000件を生成して
顧客名は、通番ではなく、日本名で妥当なものを

2025-11-27_11h02_27.png

  • 顧客名の重複が多い
    • 文字検索プラグインを使って、顧客名で集計すると重複がわかる

2025-11-27_10h41_33.png

テストデータ生成2

組合せを多くしてみた。
同姓同名のテストを考えると、ある程度重複を残した方がいいかも。

名前の重複が多いので、苗字と名前の数を増やして重複が少なくなるように

2025-11-27_11h07_08.png

  • これでも顧客名の重複が多い

テストデータ生成3

重複した顧客名を除外

まだ重複が多い。重複した顧客名を除外するようにして

2025-11-27_11h18_09.png

  • 重複なし

2025-11-27_10h49_54.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?