CATIA V5と言うより、VBAなお話です。
ちょっと行き詰まるところと申しますか、限界を感じたのでクラスを
作って対応しようと思っているところなのですが、作る以上単体テスト
っぽい事を行い、安全性を確認・確保しようと思っています。
ところが、これ自体で行き詰まるとは・・・。
問題は、数値のみの配列を返すメソッドが有り、想定外の戻り値の
場合はDebug.Assertでひっかけたいんです。
簡単な例で書くと、これです。
'vba Option Explicit Sub unit_test() Dim ary1 As Variant ary1 = Array(1, 2, 3) Debug.Assert ary1 = Array(1, 2, 3) MsgBox "Done" End Sub
これで出来ると思ったのですが、駄目なんです・・・。
配列の比較は "=" じゃダメなんですねVBAは。
やったことが無かったのですが、pythonだと出来るようです。
Python で配列の一致比較 (list, ndarray) - Qiita
それじゃ、配列の中身が一致するまでを関数で行えば良いな
と思い、こんな感じにしてみました。
'vba Option Explicit Sub unit_test() Dim ary1 As Variant ary1 = Array(1, 2, 3) 'Debug.Assert ary1 = Array(1, 2, 3) Call assert_with_array(ary1, Array(1, 2, 3)) Call assert_with_array(ary1, Array(1, 2, 4)) MsgBox "Done" End Sub Private Sub assert_with_array( _ ByVal ary1 As Variant, _ ByVal ary2 As Variant) Debug.Assert IsArray(ary1) Debug.Assert IsArray(ary2) Debug.Assert UBound(ary1) = UBound(ary2) Dim i As Long For i = 0 To UBound(ary1) Debug.Assert ary1(i) = ary2(i) Next End Sub
一回目はクリアし、二度目は引っかかります。
”おぉOKじゃん” と思ったのですが、よく考えたら何処で
assert_with_array関数を呼び出して引っかけたのかが分かりません。
調べたところ、関数の呼び出し元を知る方法は、VBAには
無さそうです。
Redirecting
世間は厳しい・・・。
pythonであれば、tracebackモジュールで呼び出し元を得られます。
C#も何か有ったのハズですが、忘れました・・・。
そこで思い付いたのが、joinで文字列にして比較すれば良いのでは?
'vba Option Explicit Sub unit_test() Dim ary1 As Variant ary1 = Array(1, 2, 3) 'Debug.Assert ary1 = Array(1, 2, 3) ' Call assert_with_array(ary1, Array(1, 2, 3)) ' Call assert_with_array(ary1, Array(1, 2, 4)) Debug.Assert Join(ary1, "") = Join(Array(1, 2, 3), "") Debug.Assert Join(ary1, "") = Join(Array(1, 2, 4), "") MsgBox "Done" End Sub
お見事! 勝手に型変換を逆手に利用した方法です。
(この方法は、検索しても見つけられませんでした)
文字列や数値等限定ですが、まぁ何も無いより良いと思ってます。
世間の皆様はどうやっているのかな?(やっていないのだろうな・・・)
追記です!
良く考えたら、文字列比較はあれじゃNGなパターンがありました。
これです。
'vba Option Explicit Sub unit_test() Dim ary1 As Variant ary1 = Array(1, 2, 3) 'Debug.Assert ary1 = Array(1, 2, 3) ' Call assert_with_array(ary1, Array(1, 2, 3)) ' Call assert_with_array(ary1, Array(1, 2, 4)) ' Debug.Assert Join(ary1, "") = Join(Array(1, 2, 3), "") ' Debug.Assert Join(ary1, "") = Join(Array(1, 2, 4), "") Dim ary2 As Variant ary2 = Array(1, 11, 111) Debug.Assert Join(ary2, "") = Join(Array(11, 1, 111), "") MsgBox "Done" End Sub
せめてセパレータを入れる必要がありますね。
Debug.Assert Join(ary2, "@") = Join(Array(11, 1, 111), "@")
さらに良く考えたら、チェックさせる関数内でDebug.Assertする
のではなく、判断した内容をBooleanで返せば良いだけの事でした。
'vba Option Explicit Sub unit_test() Dim ary1 As Variant ary1 = Array(1, 2, 3) 'Debug.Assert ary1 = Array(1, 2, 3) ' Call assert_with_array(ary1, Array(1, 2, 3)) ' Call assert_with_array(ary1, Array(1, 2, 4)) ' Debug.Assert Join(ary1, "") = Join(Array(1, 2, 3), "") ' Debug.Assert Join(ary1, "") = Join(Array(1, 2, 4), "") ' Dim ary2 As Variant ' ary2 = Array(1, 11, 111) ' Debug.Assert Join(ary2, "") = Join(Array(11, 1, 111), "") ' Debug.Assert Join(ary2, "@") = Join(Array(11, 1, 111), "@") Debug.Assert assert_array(ary1, Array(1, 2, 3)) Debug.Assert assert_array(ary1, Array(1, 2, 4)) MsgBox "Done" End Sub Private Function assert_array( _ ByVal ary1 As Variant, _ ByVal ary2 As Variant) _ As Boolean assert_array = True Select Case False Case IsArray(ary1) assert_array = False Exit Function Case IsArray(ary2) assert_array = False Exit Function Case UBound(ary1) = UBound(ary2) assert_array = False Exit Function End Select Dim i As Long For i = 0 To UBound(ary1) If ary1(i) <> ary2(i) Then assert_array = False Exit Function End If Next End Function
Debug.AssertはFalseで止まるって考えれば、これが正解な気がしてます。