Access JumpStart 2.0 | Blog

A Rapid Development Framework for Microsoft Access

In the last email, I was considering a function that would do all the comparisons of the before and after values of the FieldChanges dictionary in the AuditEventDetails object and the Input dictionary I created. This would return a Boolean. It sounds good as I say it and it will reduce our super long Assert.IsTrue line to a simple function call.

I’m starting with this function I used to just compare 1 field. Now I want to just take the two dictionaries as arguments and compare the inputs with the results, looping through. Again, here is what I started with:

Private Function FieldBeforeIsSame(FieldName As String, dctInputs As Scripting.Dictionary, dctResults As Scripting.Dictionary) As Boolean
    Dim retVal As Boolean
    retVal = (dctResults(FieldName).OldValue = dctInputs(FieldName)(0))
    FieldBeforeIsSame = retVal
End Function

First I’ll change the name of the function to something more sensible: FieldInputsMatchResults.

Private Function FieldInputsMatchResults(FieldName As String, dctInputs As Scripting.Dictionary, dctResults As Scripting.Dictionary) As Boolean
    Dim retVal As Boolean
    retVal = (dctResults(FieldName).OldValue = dctInputs(FieldName)(0))
    FieldInputsMatchResults = retVal
End Function

Now, I will remove the first argument and just leave the two dictionaries:

Private Function FieldInputsMatchResults(dctInputs As Scripting.Dictionary, dctResults As Scripting.Dictionary) As Boolean
    Dim retVal As Boolean
    Dim FieldName As Variant
    retVal = (dctResults(FieldName).OldValue = dctInputs(FieldName)(0))
    FieldInputsMatchResults = retVal
End Function

In order to keep the code compiling, I Dim’med the FieldName variable in the function as a variant. And now to loop over dctInputs and make sure the expected results are in the dctResults.

Private Function FieldInputsMatchResults(dctInputs As Scripting.Dictionary, dctResults As Scripting.Dictionary) As Boolean
    Dim retVal As Boolean
    Dim FieldName As Variant, OldMatches As Boolean, NewMatches As Boolean
    For Each FieldName In dctInputs
        OldMatches = (dctResults(FieldName).OldValue = dctInputs(FieldName)(0))
        NewMatches = (dctResults(FieldName).NewValue = dctInputs(FieldName)(1))
        retVal = (OldMatches And NewMatches)
        If retVal = False Then GoTo NoMoreMatchingNeeded
    Next FieldName
NoMoreMatchingNeeded:
    FieldInputsMatchResults = retVal
End Function

Not too bad. I’m looping, but at the first set that doesn’t fully match I set the retVal to false and end the loop.

I think this is still a bit heavy on lines and variable names, so I’m going to do another helper function to extract the old and new matches comparison. Here’s what I got:

Private Function FieldInputsMatchResults(dctInputs As Scripting.Dictionary, dctResults As Scripting.Dictionary) As Boolean
    Dim retVal As Boolean
    Dim FieldName As Variant
    For Each FieldName In dctInputs
        retVal = InputMatchesResult(CStr(FieldName), dctInputs, dctResults)
        If retVal = False Then GoTo NoMoreMatchingNeeded
    Next FieldName
NoMoreMatchingNeeded:
    FieldInputsMatchResults = retVal
End Function

Private Function InputMatchesResult(FieldName As String, dctInputs As Scripting.Dictionary, dctResults As Scripting.Dictionary) As Boolean
    Dim retVal As Boolean
    Dim OldMatches As Boolean, NewMatches As Boolean
    OldMatches = (dctResults(FieldName).OldValue = dctInputs(FieldName)(0))
    NewMatches = (dctResults(FieldName).NewValue = dctInputs(FieldName)(1))
    retVal = OldMatches And NewMatches
    InputMatchesResult = retVal
End Function

I think overall that’s a bit cleaner and my functions are closer to doing just one thing. And finally I can finish off my Test function refactor like this. And I like this a lot more:

'@TestMethod("Verify Changes")
Private Sub WhenTwoTextFieldsChangeBeforeAndAfterValuesAreReturned()
    Dim TestTextChange As AuditFieldChange, TestComboChange As AuditFieldChange
    Dim dctInputs As New Scripting.Dictionary, dctResults As Scripting.Dictionary
    dctInputs.Add "TestText", Array("TextBeforeValue", "TextAfterValue")
    dctInputs.Add "TestCombo", Array("ComboBeforeValue", "ComboAfterValue")
    Set dctResults = SetFields_ChangeThem_ReturnDictionary(dctInputs)
    Assert.IsTrue FieldInputsMatchResults(dctInputs, dctResults)
End Sub

All right! Next time I will look at potentially using the new functions to rewrite the old tests if needed. I might be able to clean it up a bit more and make it super easy to write more tests.