Monday, August 24, 2015

Side effect of struggling

I had a struggle with QList.add method – I extended the method so much I actually duplicated some ways of handling passed data. I was wondering how to describe it in the best way, so I created a yet another document for this very purpose.

During documentation I noticed I was wondering about how it will actually handle same scenarios and my solution was to create a small script, which will answer this.

It didn’t take me long before realizing this was actually inventing a wheel, because this is probably what unit testing (and ultimately TDD, Test-Driven Development) is all about.

Unit testing is for testing many small pieces of software, like methods, from different sides, in different scenarios. You call the tested code with many different input values (in different states, when present), even – or better especially – wrong ones. You may have dozens tests for a single method. Then you compare code output with expected result and if it matches, the test passed. For wrong input you set try-catch block and in the catch part you check the exception for correct one.

Because of the vast number of tests, the process is often automatized and launched after build, before commit, after server/platform software update or something like that.

My example of an unit test (in pseudo-language):

  1. // Tested method, defined somewhere else in the app:
  2. bool isNumericString(string value) { ... }
  3. // Test suite for the method isNumericString:
  4. Array testResults = [];
  5. testResults.push("Test 1: " + !isNumericString("test") ? "Passed" : "Failed"); // Unit Test 1
  6. testResults.push("Test 2: " + isNumericString("123") ? "Passed" : "Failed"); // Unit Test 2
  7. try { isNumericString(null); } catch (ex) { // Unit Test 3
  8. testResults.push("Test 3: " + ex.Type == NullException ? "Passed" : "Failed");
  9. }
  10. // and do something with testResults, like check what test failed and do nothing if all tests passed.

In TDD you start not by coding the method, but with writing such unit tests. Of course initially they all fail, because the method is blank. You define expected results for all different inputs, including many invalid ones and edge cases, and then you start making insides of the method to pass all the tests you initially created.

So I created a test suite, defined some test cases and made it compatible with QList, so it would be possible to visualize the output in a QetriX way. I also introduced com.qetrix.tests namespace.


Testing QList

I may finally get what it takes to do nice unit tests, which was probably the last big aspect of development I was still quite missing.