多型性

多型性是為不同的底層實現提供相同介面的能力

實現介面的能力允許完全將應用程式邏輯與 UI 或資料庫或此工作表或該工作表分離。

假設你有一個表單本身實現的 ISomeView 介面:

Option Explicit

Public Property Get IsCancelled() As Boolean
End Property

Public Property Get Model() As ISomeModel
End Property

Public Property Set Model(ByVal value As ISomeModel)
End Property

Public Sub Show()
End Sub

表單的程式碼隱藏可能如下所示:

Option Explicit 
Implements ISomeView

Private Type TView
    IsCancelled As Boolean
    Model As ISomeModel
End Type
Private this As TView

Private Property Get ISomeView_IsCancelled() As Boolean
    ISomeView_IsCancelled = this.IsCancelled
End Property

Private Property Get ISomeView_Model() As ISomeModel
    Set ISomeView_Model = this.Model
End Property

Private Property Set ISomeView_Model(ByVal value As ISomeModel)
    Set this.Model = value
End Property

Private Sub ISomeView_Show()
    Me.Show vbModal
End Sub

Private Sub SomeOtherSettingInput_Change()
    this.Model.SomeOtherSetting = CBool(SomeOtherSettingInput.Value)
End Sub

'...other event handlers...

Private Sub OkButton_Click()
    Me.Hide
End Sub

Private Sub CancelButton_Click()
    this.IsCancelled = True
    Me.Hide
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        Cancel = True
        this.IsCancelled = True
        Me.Hide
    End If
End Sub

但是,沒有什麼禁止建立另一個實現 ISomeView 介面的類模組而不是使用者表單 - 這可能是一個 SomeViewMock 類:

Option Explicit
Implements ISomeView

Private Type TView
    IsCancelled As Boolean
    Model As ISomeModel
End Type
Private this As TView

Public Property Get IsCancelled() As Boolean
    IsCancelled = this.IsCancelled
End Property

Public Property Let IsCancelled(ByVal value As Boolean)
    this.IsCancelled = value
End Property

Private Property Get ISomeView_IsCancelled() As Boolean
    ISomeView_IsCancelled = this.IsCancelled
End Property

Private Property Get ISomeView_Model() As ISomeModel
    Set ISomeView_Model = this.Model
End Property

Private Property Set ISomeView_Model(ByVal value As ISomeModel)
    Set this.Model = value
End Property

Private Sub ISomeView_Show()
    'do nothing
End Sub

現在我們可以更改使用 UserForm 的程式碼並使其在 ISomeView 介面上工作,例如通過將表單作為引數提供而不是例項化它:

Public Sub DoSomething(ByVal view As ISomeView)
    With view
        Set .Model = CreateViewModel
        .Show
        If .IsCancelled Then Exit Sub
        ProcessUserData .Model
    End With
End Sub

因為 DoSomething 方法取決於的介面(即,上抽象 ),而不是一個具體的類 (例如一個特定的 UserForm),我們可以寫出一個自動化單元測試,以確保當 view.IsCancelledTrue ProcessUserData 不執行,通過使我們的測試建立一個 SomeViewMock 例項,將其 IsCancelled 屬性設定為 True,並將其傳遞給 DoSomething

可測試程式碼取決於抽象

可以在 VBA 中編寫單元測試,有些外掛甚至可以將它整合到 IDE 中。但是當程式碼與工作表,資料庫,表單或檔案系統緊密耦合時,單元測試開始需要實際的工作表,資料庫,表單或檔案系統 - 而這些依賴性是新的失控失敗這點可測試的程式碼應隔離,從而使單元測試並不需要一個實際的工作表,資料庫,表格或檔案系統。

通過編寫針對介面的程式碼,以允許測試程式碼注入存根/模擬實現的方式(如上面的 SomeViewMock 示例),你可以在受控環境中編寫測試,並模擬 42 箇中的每一個可能發生的情況。表單資料上的使用者互動的排列,甚至沒有一次顯示錶單並手動單擊表單控制元件。