VBAに単体テストの考え方を取り入れる方法|Debug.Printとテスト用Subの作り方

VBAに単体テストの考え方を取り入れるには、処理をFunctionに小分けして、テスト専用のSubで結果を確認するだけです。難しい専用ツールは不要で、MsgBoxDebug.Print を使えばすぐに始められます。

この記事では、次の内容を順番に解説します。

  • 単体テストとは何か(VBAでの考え方)
  • テスト用プロシージャの作り方
  • Debug.Printを使ったログ確認
  • 複数パターンのテストのまとめ方
  • 実務でよく使うテストのパターン例

単体テストとは何かを理解するには?

単体テスト(ユニットテスト)とは、プログラムの「部品」ごとに正しく動くかを確認するテストのことです。マクロ全体を一気に動かして「うまくいった/いかなかった」で判断するのではなく、小さな処理単位ごとに「この部分は正しい」と確かめながら組み上げる考え方です。

VBAに単体テストの考え方が向いている理由は次の3つです。

  • 処理をFunctionに分けやすい:VBAは複数のプロシージャやFunctionで構成できるため、テスト単位を作りやすい。
  • 結果がシートで目視確認できる:Excelというシートという「見える場所」があるので、期待値と実際の値を比べやすい。
  • 確認マクロを作るだけで導入できる:専用のテストフレームワークがなくても、MsgBoxDebug.Print だけで始められる。

テスト用プロシージャを作るには?

まず、テスト対象となるFunctionを用意します。次の例は価格に消費税10%を加算して返す関数です。

Function AddTax(price As Double) As Double
    AddTax = price * 1.1
End Function

この関数が正しく動くかを確認するテスト用Subを別に作ります。

Sub Test_AddTax()
    Dim result As Double
    result = AddTax(1000)

    If result = 1100 Then
        MsgBox "OK:AddTaxは正常に動作しています。"
    Else
        MsgBox "NG:AddTaxの結果が想定外です → " & result
    End If
End Sub

ポイントは「期待する値(1100)」と「実際の結果(result)」を比較していることです。このパターンさえ覚えれば、どんなFunctionでもテストできます。

テストの要素内容
入力値テストに使う引数(例:1000)
期待値正しく動いたときの結果(例:1100)
実際の結果Functionが返した値(result)
判定期待値 = 実際の結果 → OK / 違う → NG

Debug.Printでログを確認するには?

毎回 MsgBox を使うと「OK」を押す手間がかかります。複数のテストをまとめて実行したい場合は Debug.Print を使うと便利です。結果はVBEの「イミディエイトウィンドウ」(CtrlG)に出力されます。

Sub Test_AddTax_Log()
    Dim result As Double
    result = AddTax(200)

    If result = 220 Then
        Debug.Print "Test_AddTax(200):OK"
    Else
        Debug.Print "Test_AddTax(200):NG → " & result
    End If
End Sub

実行後にイミディエイトウィンドウを確認すると「Test_AddTax(200):OK」のように表示されます。MsgBox と違い、クリックせずに複数の結果をまとめて確認できます。

複数パターンをまとめてテストするには?

境界値や特殊な入力(0・負の数・大きな値)でも正しく動くかを確認しておくと、本番で予期しないエラーが起きにくくなります。

Sub Test_AddTax_All()
    ' 通常ケース
    Debug.Print "100 → "; AddTax(100)    ' 期待値:110
    ' ゼロ
    Debug.Print "0 → "; AddTax(0)        ' 期待値:0
    ' 負の数
    Debug.Print "-100 → "; AddTax(-100)  ' 期待値:-110
    ' 大きな値
    Debug.Print "10000 → "; AddTax(10000) ' 期待値:11000
End Sub

さらに判定まで自動化したい場合は次のようにまとめます。

Sub Test_AddTax_Auto()
    Dim passCount As Long
    Dim failCount As Long

    ' テストケースを配列で管理
    Dim inputs(3)   As Double
    Dim expects(3)  As Double

    inputs(0) = 100:   expects(0) = 110
    inputs(1) = 0:     expects(1) = 0
    inputs(2) = -100:  expects(2) = -110
    inputs(3) = 10000: expects(3) = 11000

    Dim i As Long
    For i = 0 To 3
        If AddTax(inputs(i)) = expects(i) Then
            Debug.Print "OK:入力=" & inputs(i)
            passCount = passCount + 1
        Else
            Debug.Print "NG:入力=" & inputs(i) & " 結果=" & AddTax(inputs(i)) & " 期待=" & expects(i)
            failCount = failCount + 1
        End If
    Next i

    Debug.Print "---"
    Debug.Print "合計:OK=" & passCount & " / NG=" & failCount
End Sub

実務でよく使うテストパターンとは?

単体テストが特に効果を発揮するのは、次のような実務でよく使う処理です。

文字列処理のテスト

' テスト対象:文字列の長さチェック関数
Function CheckLength(txt As String) As String
    If Len(txt) > 10 Then
        CheckLength = "長すぎます"
    ElseIf Len(txt) = 0 Then
        CheckLength = "未入力です"
    Else
        CheckLength = "OK"
    End If
End Function

' テスト用プロシージャ
Sub Test_CheckLength()
    Debug.Print CheckLength("")           ' 期待値:未入力です
    Debug.Print CheckLength("abc")        ' 期待値:OK
    Debug.Print CheckLength("12345678901") ' 期待値:長すぎます(11文字)
End Sub

日付処理のテスト

' テスト対象:当月かどうか判定する関数
Function IsCurrentMonth(targetDate As Date) As Boolean
    IsCurrentMonth = (Year(targetDate) = Year(Date) And Month(targetDate) = Month(Date))
End Function

' テスト用プロシージャ
Sub Test_IsCurrentMonth()
    Debug.Print IsCurrentMonth(Date)                    ' 期待値:True(今日)
    Debug.Print IsCurrentMonth(DateAdd("m", -1, Date))  ' 期待値:False(先月)
    Debug.Print IsCurrentMonth(DateAdd("m", 1, Date))   ' 期待値:False(来月)
End Sub

セルの値を使った処理のテスト

' テスト対象:セルの値が数値かどうかチェックする関数
Function IsValidScore(val As Variant) As Boolean
    If IsNumeric(val) Then
        If val >= 0 And val <= 100 Then
            IsValidScore = True
        Else
            IsValidScore = False
        End If
    Else
        IsValidScore = False
    End If
End Function

' テスト用プロシージャ
Sub Test_IsValidScore()
    Debug.Print IsValidScore(80)    ' 期待値:True
    Debug.Print IsValidScore(0)     ' 期待値:True(境界値)
    Debug.Print IsValidScore(100)   ' 期待値:True(境界値)
    Debug.Print IsValidScore(101)   ' 期待値:False(範囲外)
    Debug.Print IsValidScore("abc") ' 期待値:False(文字列)
    Debug.Print IsValidScore("")    ' 期待値:False(空白)
End Sub

まとめ

  • 単体テストの考え方:処理を小さなFunctionに分け、テスト専用のSubで「入力→期待値→実際の結果」を比較する。
  • MsgBox:1つの処理を確認するシンプルな方法。
  • Debug.Print:複数のテストをまとめて実行し、イミディエイトウィンドウで確認する方法。クリック不要で効率的。
  • 複数パターンのテスト:通常ケース・ゼロ・負の数・境界値を用意しておくと本番での予期しないエラーを防げる。
  • 実務での使いどころ:文字列チェック・日付処理・セル値の検証など、繰り返し使うFunctionほどテストの効果が高い。

よくある質問

テスト用のSubはどこに書けばいいですか?

本番のコードとは別の標準モジュールを作って、そこにまとめて書くのがおすすめです。モジュール名を「Test_Module」などにしておくと、本番コードと区別しやすくなります。リリース前にテスト用モジュールだけ削除するか、非表示にすることもできます。

SubではなくFunctionにする基準は何ですか?

「値を返す処理」はFunctionにするのが基本です。例えば計算・判定・文字列の変換など、「何かを入れると何かが返ってくる」処理はFunctionが向いています。Subは「保存する」「シートを更新する」など副作用のある処理に使います。Functionにしておくとテストがしやすくなります。

Debug.Printの結果はどこで確認できますか?

VBEを開き(AltF11)、メニューの「表示」→「イミディエイトウィンドウ」か CtrlG で開けます。マクロを実行するとそこに出力されます。イミディエイトウィンドウは画面下部に表示されます。

テストを書く手間が増えませんか?

最初は手間に感じますが、マクロの規模が大きくなるほどテストの効果が出ます。特に「仕様を変えたとき」「他の人が使うとき」に、テストがあると修正後の動作確認が一瞬で終わります。小さなFunctionを1つ作るたびに3〜4行のテストSubを追加する習慣をつけると無理なく続けられます。

マクロ全体のテストはどうすればいいですか?

全体の流れをテストする場合は、テスト用のシートやデータを別途用意して実行するのが現実的です。本番データを直接使わず、テスト用の入力データ・期待する出力結果を用意しておいて、マクロ実行後にセルの値を確認します。本番環境とテスト環境をシートで分けておくと安全に繰り返しテストできます。


動画で学びたい方へ

「記事を読んでも、実際に自分で書けるか不安…」という方には、動画で基礎からじっくり学べる講座がおすすめです。

VBAが初めての方を前提に、つまずきやすいポイントを先回りして解説しています。サンプル動画は無料でご覧いただけます。

動画で学ぶExcelマクロ|JIMOVEオンラインスクール

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール