This week the course is covering another two very important topics: Testing and Specifications.
LECTURE 3: Testing
Testing is a very important part of creating functionally correct programs.
Testing will be always incomplete
You will try to test your program using three methods:
- Formal Reasoning, essentially you manually verify that your program works correctly
- Code Review: Another Programmer takes a look and says everything is ok.
- Test Suites: Essentially you write another program (which can have its own bugs) to test your program. You define the inputs and the expected output and compare them.
The course mentions again the residual defect rates of 1-10 defects/kloc(1000 lines of code). Again this does not cite where this number actually comes from. Especially when using Industry Standards and Test Suites this high number would drastically drop to a much lower number. However, in the end, it only would remain to be an assumption since the actual number cannot be determined. You testing your program for every possible input (Exhaustive testing) is not feasible. The strategy to simply take a look and see if it works (Haphazard testing) will also not reveal all bugs. The same is true for "Random" testing. All of these test methods cannot be used to test software.
When you are writing tests you should think about how you can make your program fail. Test drive development takes the following approach.
- Specify what you want to program
- Write tests that would test the specification
- Write code so that your code passes the tests
The specification is key to define what inputs are possible and which outputs will be produced. (This also includes throwing errors) Blackbox testing only focuses on the input and output of the function. These tests do not take into account how the algorithm actually works. The alternative is Whitebox testing takes into account how the program is implemented.
Now that you have written tests for all of your code, did you also test all of your code? Coverage takes a look at if all Statements and all possible paths through your code are covered. There are various Code coverage tools available that you can run and then visually see which part of the code is covered by your tests. In reality, you should try to achieve a coverage of 70-90% of your code achieving 100% is usually not possible due to time constraints. Of course, this is not the case if you are using Test Driven Development.
Usually, you would create a testsuite of Unit Tests. You should integrate these tests into your build process to ensure that the tests run automatically. Especially when you modify existing code this will ensure that your modifications will not accidentally break something unintentionally. When working with multiple people you should add hooks to your git repository that it rejects code that does not pass your test suite.
LECTURE 4: Specifications
This lecture is going to cover preconditions and post-conditions in method specifications, and how to write correct specifications.
What is a specification?
The lecture defines a specification primarily only concerning how the interfaces are defined and how the specification document essentially is used as a communication device to talk to the client. Now, this actually assumes that the client is another programmer that wants the module/system to do a specific functionality. In my work experience usually, the client has no technical background and expects the programmer to know what he wants. Yes, the specification is the key document on how to negotiate which features etc. the client requires, it is however not exactly defined which functions or how interfaces should be created, this is usually the task of the programmer. The course actually is more talking about a documentation document how and which interfaces exist in the code you are programming for the client. The documentation is key whenever other programmers need to use the code you have programmed. In either case, the specification document is a key document. It defines the work that needs to be done. The document shields the programmer from the client, if the client forgot to specify something, thus the programmer did not implement it he can prove it was the client's fault. At the same time, the programmer is bound to the document that he actually implements all features. (or negotiates, talks with the client that the functionality is unfeasible, or not possible to be implemented)
Pre and Post Conditions
For each function, you require the preconditions (what inputs) and postconditions (what outputs). The inputs may have to have a specific structure, cannot be a certain value etc. These need to be checked. The function also will have various outputs. This is, of course, the result, and how the result should be structured, the method also can throw errors.
Write test cases
Essentially if the specification of the function is well defined it is very easy to write the test cases. You simply follow the specification write tests to get the expected correct results and willfully pass wrong arguments into the function. The rest of the lecture covers how to throw Exceptions. Which to use when.
Again another batch of "Java Tutor" exercises. They were as exciting as the last batch... However this time they also provided a "warm-up" problem set. The warm-up is just to implement the mathematical "quadratic roots formula". The straightforward implementation of the formula will not pass all the Unit Tests. You need to take a deeper look at Java to actually figure out why the last Unit Test fails, and how you can change your code to make your code pass the test.