t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA Debug.Assertの使い方

以下のプログラムを実行すると、ランダムな数値が出力される。

Sub BugSample()
    Dim Arr(1 To 10) As Long
    Dim UpperBound As Long: Upper = 1000
    Dim LowerBound As Long: Lower = 10

    Dim i As Integer
    For i = 1 To 10
        Arr(i) = Int((UpperBound - LowerBound + 1) * Rnd + LowerBound)
    Next
    
    Dim j As Integer
    For j = 1 To 10
        Debug.Print Arr(j)
    Next
End Sub

…嘘である。

わざとらしいバグなので一見してすぐに気付いた人もいるかもしれないが、これを実行してもイミディエイトウインドウには0が10個並ぶだけである。

バグは変数名である。UpperBoundとして変数宣言しているのに、実際にはUpperに代入している。LowerBoundも同様だ。

こういうバグが生まれるのは、コーディングの途中で変数名が分かりづらいことに気づき、直したはいいが一部直し忘れたようなケースである。Option Explicitである程度防ぐことはできるものの、実務のコードは複雑で、必ずしもそれで万全とは言えない。

実際にはこのように間に処理がはさまっていて、Upper、Lowerもちゃんと宣言されて別の用途で使われているケースもある。すると、Option Explicitには引っかからず、バグの原因に頭を悩ませることになる。

Option Explicit
Sub BugSample()
    '~処理×20行~
    Dim Upper As Long
    Dim Lower As Long
    '~処理×30行~
    Dim Arr(1 To 10) As Long
    Dim UpperBound As Long: Upper = 1000
    Dim LowerBound As Long: Lower = 10
    '~処理×10行~
    Dim i As Integer
    For i = 1 To 10
        Arr(i) = Int((UpperBound - LowerBound + 1) * Rnd + LowerBound)
    Next
    '~処理×10行~
    Dim j As Integer
    For j = 1 To 10
        Debug.Print Arr(j)
    Next
    '~処理×5行~
End Sub


そこで、For文の中に、Debug.Assertを埋め込んでおく。

    For i = 1 To 10
        Debug.Assert LowerBound >= 10
        Debug.Assert UpperBound <= 1000
        Arr(i) = Int((UpperBound - LowerBound + 1) * Rnd + LowerBound)
    Next

Debug.Assertは、「こうなるはず」という条件を指定しておき、そうならなかった場合にプログラムを中断させる機能である。
LowerBound変数は10以上のはず→Debug.Assert LowerBound >= 10
UpperBound変数は1000未満のはず→Debug.Assert UpperBound <= 1000

実行すると、プログラムは条件の不成立を発見し、停止する。
f:id:t-hom:20160114093935p:plain

If文とStop文の組み合わせでも、似たようなことはできる。
f:id:t-hom:20160114094222p:plain

しかし、If文は単に「条件を満たしたら停止するんだな」という以上の意味を持たない。
Debug.Assertの方は「こうなるはず」というプログラマの考えを読み取ることができる。

また、前回紹介したウォッチウインドウでも条件の監視はできる。
thom.hateblo.jp

ただし、ウォッチウインドウではプログラム全体を通して条件成立を監視することはできるが、コードの特定個所での条件成立をピンポイントで監視することはできない。

Debug.Assertはコードの特定の時点での条件不成立を監視する。ウォッチウインドウとは逆である。ただ、Notを付ければ反転できるので条件指定の機能は同等と考えて良い。

異常を前もって知らせるためにDebug.Assertは便利である。
プログラムが完成したら、保守に備えてコメントアウトしておくと良い。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。