忍者ブログ

リファクタリング用シート比較自動試験マクロ

2022年05月27日
最近、「プログラマが知るべき97のこと」という書籍を読んで影響を受けた話。

・わかりやすいコメントを書くより、リファクタリングでわかりやすいソースコードを書くこと
・コードに書けないことのみをコメントすること
・このコードで何がしたいかコメントだけでわかること
・美はシンプルさに宿る
・自動テストで設計品質を確保


個人的によく使ってるマクロに「選択列の項目の内訳を出すマクロ」がある。※1
このマクロを改良するためコピペで別プロシージャを作ったものの、
100行超えるソースのたった1箇所を変えた別プロシージャを作るのは美しくない。

処理の共通化が必要になってくるので、設計変更に着手する前に
出力されるシートが正しいかを自動的にテストするマクロを作ってみた。


※1 「選択列の項目の内訳を出すマクロ」は、「アパッチのWEBアクセスログの集計④」で登場しました。
https://aki.p-kin.net/Entry/6/


【UI設計】使用方法
最初に考えたのは、2つのシートを選択してシート比較ボタンを押す処理。
office tanakaで「ActiveWindow.SelectedSheets」の使い方を知った)


何回か試験しているうちに気づいた。いちいちシート2つ選ぶのめんどくさいと。
なので、予め決めておいた名前のシートがあればそれと比較する仕様にした。

【UI設計】結果表示
リファクタリング目的なので、値が同じならOKと割り切り。

2つのシートで値の入った範囲が違えば不一致で終了。
範囲が同じで値の不一致があっても10以上なら数だけ表示。
10以内なら場所と値を表示する。


ちなみに、ファイル出力するマクロだったら
コマンドプロンプトのfcコマンドで比較できる。都度打つのはめんどくさいので、
コマンドをクリップボードに送るバッチファイルで楽をする。


以下ソース。
ソースのテキストファイルは こちらから。



Option Explicit

Sub シート比較自動試験()
Const refSHname = "refSH" '比較対象シート名
If ActiveSheet.Name = refSHname Then msgEnd ("他のシートを選択して実行してください。")

'refSHnameシートがあるか判定
Dim sh As Long, rWS As Worksheet, tWS As Worksheet
For sh = 1 To Worksheets.Count
If Worksheets(sh).Name = refSHname Then
Set rWS = Worksheets(sh)
Set tWS = ActiveSheet
End If
Next sh

'2シート選択されてるか判定
If ActiveWindow.SelectedSheets.Count = 2 Then
Set rWS = ActiveWindow.SelectedSheets(1) '比較対象
Set tWS = ActiveWindow.SelectedSheets(2) 'test対象
ElseIf rWS Is Nothing Then
msgEnd ("2シート選択するか比較対象シート名を「 " & refSHname & " 」に変更してください。")
End If

'UsedRange比較と値の比較をして、結果を出力メッセージ用変数に格納
Dim uRangeDiff As Boolean, r As Variant, rValue As String, cnt As Long, rMsg As String
If tWS.UsedRange.Address <> rWS.UsedRange.Address Then
uRangeDiff = True
rMsg = "UsedRangeが異なります。" & Chr(10)
rMsg = rMsg & Chr(10)
rMsg = rMsg & tWS.Name & "   " & rWS.Name & Chr(10)
rMsg = rMsg & "[" & Replace(tWS.UsedRange.Address & "] ⇔ [" & rWS.UsedRange.Address, "$", "") & "]"
Else
For Each r In tWS.UsedRange
If tWS.range(r.Address).Value <> rWS.range(r.Address).Value Then
cnt = cnt + 1
rMsg = rMsg & Chr(10) & Replace(r.Address, "$", "") & " [" & tWS.range(r.Address) & "] ⇔ [" & rWS.range(r.Address) & "]"
End If
Next r
End If

'結果表示
If uRangeDiff = True Then
MsgBox rMsg, vbOKOnly, "範囲エラー"
ElseIf cnt > 0 Then
If cnt > 10 Then
MsgBox cnt & "箇所違います", vbOKOnly, "値エラー"
Else
MsgBox (cnt & "箇所違います" & Chr(10) & Chr(10) & "Range " & tWS.Name & "   " & rWS.Name & rMsg), vbOKOnly, "値エラー"
End If
Else
MsgBox rWS.Name & "と" & tWS.Name & "に相違点はありません"
End If
End Sub

Private Sub msgEnd(msg)
'メッセージを出して処理終了
MsgBox msg
End 'exit subじゃない
End Sub


PR
Comment
  Vodafone絵文字 i-mode絵文字 Ezweb絵文字