Access JumpStart 2.0 | Blog

A Rapid Development Framework for Microsoft Access

A big part of Test Driven Development is to write code that passes a test without overthinking things.

In my last test I wrote, it’s pretty clear it will not stand up to the next couple of tests one might think of.

The test is making sure that the count of updates to the field is 1 when I made 1 update. The test is as follows:

'@TestMethod("FormListener")
Private Sub FormListenerReturnsCountOfOneForTestTextField()
    On Error GoTo TestFail
    FormListenerTest.Setup NewForm
    NewForm.TestText = "TestingUpdate"
    DoCmd.RunCommand acCmdSaveRecord
    Assert.AreEqual FormListenerTest.TimesFieldChanged("TestText"), CLng(1)

TestExit:
    '@Ignore UnhandledOnErrorResumeNext
    On Error Resume Next
    
    Exit Sub
TestFail:
    Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
    Resume TestExit
End Sub

The code I wrote to pass this test is an example of not thinking, and just writing something that will pass:

Public Function TimesFieldChanged(theFieldName As String) As Long
    Dim retVal As Long
    retVal = 1
    TimesFieldChanged = 1
End Function

You can see that I simply wrote the function to pass back the value that would pass the single test I’ve written so far.

I’m just pausing here to note that this code is clearly going to change, is not generalized, and is basically placeholder code to pass the test. This is by design. Rather than try to get ahead of the tests, in TDD we want to literally just write something simple enough to get the test to pass. Simplicity is the goal, the complexity comes and evolves the code as we add more tests.

I think in this case, I’m just going to write another failing test to get a 0 or a 1 and I’m going to combine these two asserts into the same test. Is that a good idea? I don’t really know. It simplifies my test code a little and prevents me from copying lots of code though. Maybe I’ll refactor it in a different way later, but for now, Let’s do this:

'@TestMethod("FormListener")
Private Sub FormListenerReturnsCountOfOneForTestTextField()
    On Error GoTo TestFail
    FormListenerTest.Setup NewForm
    Assert.AreEqual FormListenerTest.TimesFieldChanged("TestText"), CLng(0)
    NewForm.TestText = "TestingUpdate"
    DoCmd.RunCommand acCmdSaveRecord
    Assert.AreEqual FormListenerTest.TimesFieldChanged("TestText"), CLng(1)

TestExit:
    '@Ignore UnhandledOnErrorResumeNext
    On Error Resume Next
    
    Exit Sub
TestFail:
    Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
    Resume TestExit
End Sub

This of course causes the test to fail since I coded the test to return 1. I probably should have started with the 0 actually. I made a mistake there.

After running the above test, I was getting some wonky responses from the RubberDuck test explorer, so I am making a copy of the function and doing one test for 0 and one test for 1. Now the 0 test passes and the 1 test fails.

Now it is time to add code to see if the TestText field can change and return 1.

Stop Jon! As I look to see what kind of code I need to add to make this function return 1 I am seeing that I have to do a lot of coding. I would need to start tracking all the field names and whether it got updated and place that result in some kind of collection or array and iterate over it. Seems like way too much coding for one test. I think I have gone down the wrong track. Let me re-think this and we will try to find my error in a future email.