1 |
2 |
drasko |
|
2 |
|
|
|
3 |
|
|
TESTING HOWTO
|
4 |
|
|
|
5 |
|
|
By Bahadir Balban
|
6 |
|
|
|
7 |
|
|
HOW TO ADD TESTS
|
8 |
|
|
|
9 |
|
|
Tests in this project are meant to test basic functionality of the microkernel
|
10 |
|
|
but cover test cases comprehensively. The special trait with these tests is
|
11 |
|
|
that each is meant to test only one aspect of the microkernel, rather than
|
12 |
|
|
trying to test multiple aspects at once.
|
13 |
|
|
|
14 |
|
|
A benefit of having this approach is that when a test fails, it is easier to
|
15 |
|
|
spot the problem as opposed to a failure that is caused by a complex
|
16 |
|
|
interaction of multiple aspects of the microkernel.
|
17 |
|
|
|
18 |
|
|
The software must be also tested for more complex interactions, but these
|
19 |
|
|
tests are not the place to create them. When a new test is added, it must cover
|
20 |
|
|
a valid test case but the test itself must be as shallow as possible.
|
21 |
|
|
|
22 |
|
|
|
23 |
|
|
EXAMPLE
|
24 |
|
|
|
25 |
|
|
A thread creation test, while using other aspects of the microkernel such as
|
26 |
|
|
the l4_exchange_registers system call, should only test thread creation aspect
|
27 |
|
|
of the microkernel. A separate l4_exchange_registers test would need to be
|
28 |
|
|
created who then uses the thread creation aspect of the microkernel, but only
|
29 |
|
|
testing the parameters to l4_exchange_registers system call, covering it
|
30 |
|
|
exhaustively. In essence, each test must be shallow in itself, and have a single
|
31 |
|
|
focus.
|
32 |
|
|
|
33 |
|
|
|
34 |
|
|
Here's a step-by-step approach to testing:
|
35 |
|
|
|
36 |
|
|
1.) Create one test that tests one thing well.
|
37 |
|
|
This is about the above paragraphs. Test one aspect, so we know that that
|
38 |
|
|
aspect is functional. When there are lots of changes to code and many
|
39 |
|
|
invariables, this will make sure that these tests are one solid invariable
|
40 |
|
|
in the equation. They should be as deterministic and simple as possible
|
41 |
|
|
so that other variants can be debugged using the tests as anchor points.
|
42 |
|
|
|
43 |
|
|
Each test must be significantly simple. E.g. If I have 2 test cases that
|
44 |
|
|
require slightly differing input to a test function, I would not use a
|
45 |
|
|
loop of i = 0..2 where parameters change when i == 0 and i == 1. That
|
46 |
|
|
would be difficult to understand, and complicated. Instead, each of those
|
47 |
|
|
inputs should be 2 test cases. This way, I focus %100 on the debugged code,
|
48 |
|
|
I don't put a tiny fraction of my focus trying to understand the test.
|
49 |
|
|
|
50 |
|
|
2.) Number (1) is unexpectedly hard to achieve. Especially a person who is
|
51 |
|
|
accustomed to design complex systems that work will have a hard time in
|
52 |
|
|
applying an approach that is completely the opposite. Make sure to stop
|
53 |
|
|
thinking smart and get used to thinking not moderately dumb but very dumb.
|
54 |
|
|
|
55 |
|
|
3.) Make sure to escalate errors properly.
|
56 |
|
|
When porting to a new architecture or where there are lots of variables,
|
57 |
|
|
your tests will fail. It is an extra burden to find out how. Error
|
58 |
|
|
escalation provides a quick and easy means to provide error details.
|
59 |
|
|
|
60 |
|
|
4.) Make sure to print only when necessary.
|
61 |
|
|
Tests should print out values only when a tested aspect goes wrong.
|
62 |
|
|
a) It should describe what the test was trying to do, i.e. describe what
|
63 |
|
|
was expected to happen. This way it is quicker to see expected results.
|
64 |
|
|
b) It should describe what has happend, contrary to expected. This should
|
65 |
|
|
tell what went wrong.
|
66 |
|
|
c) It should tell no more. Printout clutter is a huge negative factor in
|
67 |
|
|
making tests effective.
|
68 |
|
|
|
69 |
|
|
4.) Complicating the tests:
|
70 |
|
|
It is often necessary that simple tests must be the building blocks for
|
71 |
|
|
more complicated tests so that complicated interactions in the system
|
72 |
|
|
can be tested.
|
73 |
|
|
|
74 |
|
|
Complicating the test cases should be done with a systematic approach:
|
75 |
|
|
|
76 |
|
|
a) Tests are like building blocks. Each test that tests one aspect of the
|
77 |
|
|
software should be designed as a rock solid way of testing that one
|
78 |
|
|
aspect. See (1) above for the first step. Design extremely simple tests.
|
79 |
|
|
|
80 |
|
|
b) A design should be carefully made such that multiple aspects as
|
81 |
|
|
described in (a) provide a highly deterministic and reproducable
|
82 |
|
|
sequence of events when combined together. While this significantly
|
83 |
|
|
narrows down the tested domain of functionality, it equally much ensures
|
84 |
|
|
that the test case is covered in full control, thus should anything
|
85 |
|
|
go wrong and test fails, it is much easier to find out what went wrong.
|
86 |
|
|
|
87 |
|
|
E.g. a test that randomly creates threads would be almost useless since
|
88 |
|
|
any failure of the test would be irreproducable and very hard to use
|
89 |
|
|
to recover any bug.
|
90 |
|
|
|
91 |
|
|
c) Test cases should slowly and surely grow into a larger domain of
|
92 |
|
|
functionality by rigorously and systematically following steps (a) and
|
93 |
|
|
(b). If these steps are not rigorously followed, the tests would be
|
94 |
|
|
diluted in quality, and the testing structure would quickly become a
|
95 |
|
|
mess.
|
96 |
|
|
|
97 |
|
|
Some examples:
|
98 |
|
|
~~~~~~~~~~~~~~
|
99 |
|
|
1) Test 1: Extended ipc on already mapped pages.
|
100 |
|
|
2) Test 2: Extended ipc on page faulting pages.
|
101 |
|
|
3) Test 3: Extended ipc on page faulting pages, but non contiguous
|
102 |
|
|
physical pages.
|
103 |
|
|
4) Test 4: Extended ipc on page faulting pages, but non contiguous
|
104 |
|
|
physical pages, and between threads in different address spaces.
|
105 |
|
|
5) Test 5: Extended ipc on page faulting pages, but non contiguous
|
106 |
|
|
physical pages, and between threads in different address spaces,
|
107 |
|
|
but using the same virtual addresses on both threads.
|
108 |
|
|
|
109 |
|
|
You see, a single ipc test is systematically growing into a more complex
|
110 |
|
|
test, but at each step, only one possibly variable aspect is added and
|
111 |
|
|
tested. The other test aspects have already been validated by earlier,
|
112 |
|
|
simpler combinations of test cases.
|
113 |
|
|
|
114 |
|
|
|