Up to Main Index Up to Journal for October, 2018 JOURNAL FOR MONDAY 8TH OCTOBER, 2018 ______________________________________________________________________________ SUBJECT: More updates + A testing light bulb moment DATE: Mon 8 Oct 20:45:25 BST 2018 October already? Not long till Halloween :) I’ve been looking at the changes on the public dev branch to see if there are enough to justify my usual Halloween release. I think there is. The last release was in July, so it’s about time all of the new changes were rolled up and rolled out. Public dev branch has just been updated with some more fixes and updates. Decoding a Duration now rounds (half up) to the nearest second. Otherwise decoding and encoding a duration could produce different results. Decoding a DateTime now strips leading/trailing white space. The tests for encoding and decoding Bytes have been cleaned up. I’ve actually separated the tests into two functions: TestBytes and TestBytesSideEfects. Originally I was trying to test the result of calling Bytes and test for side effects from the call — such as the passed parameter being modified and making sure a copy was being returned. This proved to be a mistake as it made the tests overly complicated. In the tests for Bytes I wanted to make sure that a copy of the data was returned and not a re-slicing of the passed slice. So I used a technique I’d seen before and compared the addresses of the last possible element in each slice: haveEnd := &have[0:cap(have)][cap(have)-1] wantEnd := &want[0:cap(want)][cap(want)-1] if haveEnd == wantEnd { t.Errorf("have and want overlap: %+q", have) } However, with the introduction of full indexing expressions, this is no longer a viable solution — as the cap for a slice can now be changed. Although I did notice in Go 1.11.1 it’s still used in the alias function in math/big/nat.go. I’m guessing as the function is not exported the slices are controlled and full indexing is known not to be used or an issue? I went on a long hunt for another solution. I tried various options using the reflect and unsafe packages, nothing worked and the code was becoming more convoluted. I finally came to my senses, which was when I split up the main tests from the tests for side effects. It was also when I realised there was an easy way to test if the result returned from Bytes overlapped with the original array — I simply overwrote the results! To start with, I manually created a backing array so I had access to it. Then I sliced it to create my parameter for Bytes. The result of calling Bytes was then overwritten. If the backing array changed due to the overwriting then the resulting slice was not a copy. I had a similar situation with the decode.DateTime tests. I needed to add tests for trying to parse invalid date/time strings. Initially I tried shoehorning the additional checking into the TestDateTime function. That turned into another convoluted mess. Again I split the additional tests out into a separate test function — TestDateTimeInvalid. I don’t know where I got the notion of one testing function per function being tested came from initially? Having multiple, very specific test functions hitting a function under test in different ways keeps the tests very simple. Don’t you just love it when you have those sudden moments of clarity? In hindsight it’s obvious really. We break complex code down into multiple functions, each with a specific purpose. So why not apply it to writing tests as well? I’ll have to look at my other tests and see which ones could benefit from being split up and improved. -- Diddymus Up to Main Index Up to Journal for October, 2018