| Next revision | Previous revision |
| sysunit [2018/03/20 20:26] – RyanStone | sysunit [2018/03/28 22:35] (current) – RyanStone |
|---|
| ==== 1. Stubs ==== | ==== 1. Stubs ==== |
| |
| A stub is a minimal implementation of a function. Frequently a stub will always return a single hard-coded value. Stubs are most frequently used when the code unit needs to link against a particular symbol, but the subset of the code unit that is actually being tested never calls that symbol. For example, if a kernel source file defines some sysctl handlers that call sysctl_handle_int() but your test suite does not invoke the sysctl handlers, a stub for sysctl_handle_int() would be an appropriate mechanism. In the specific case where the tester believes that a stub will never be called and it is only being provided to make the unit test link, it can be a good idea to have the stub unconditionally call abort(). That way, if the code under test unexpectedly calls the stub the tester gets immediate feedback that their understanding of how the code under test is being invoked was wrong. | A stub is a function implementation whose behaviour never varies. Frequently a stub will always return a single hard-coded value. Stubs are most frequently used when the code unit needs to link against a particular symbol, but the subset of the code unit that is actually being tested never calls that symbol. For example, if a kernel source file defines some sysctl handlers that call sysctl_handle_int() but your test suite does not invoke the sysctl handlers, a stub for sysctl_handle_int() would be an appropriate mechanism. In the specific case where the tester believes that a stub will never be called and it is only being provided to make the unit test link, it can be a good idea to have the stub unconditionally call abort(). That way, if the code under test unexpectedly calls the stub the tester gets immediate feedback that their understanding of how the code under test is being invoked was wrong. |
| |
| ==== 2. Fakes ==== | ==== 2. Fakes ==== |
| |
| A fake is a re-implementation of a function. A fake may only provide a subset of the functionality of the real API if the code under test doesn't require the full range of functionality. The distinction between a fake and a stub is fairly blurry, but typically if the function has any logic at all it would be termed a fake rather than a stub. A plausible example of a fake of malloc(9) would be a function that calls the real libc malloc() and then conditionally zeroes the memory (based on the M_ZERO flag). | A fake is a function implementation whose behaviour varies based on the parameters passed in. A fake may only provide a subset of the functionality of the real API if the code under test doesn't require the full range of functionality. The distinction between a fake and a stub is fairly blurry, but typically if the function has any logic at all it would be termed a fake rather than a stub. A plausible example of a fake of malloc(9) would be a function that calls the real libc malloc() and then conditionally zeroes the memory (based on the M_ZERO flag). |
| |
| ==== 3. Mock ==== | ==== 3. Mock ==== |
| |
| A mock is an implementation of an API whose behaviour is configurable by the test case. Mocks can, for example, verify that function parameters meet requirements set by the test case, return canned values based on programmable criteria (e.g. return failure on the third call or return failure if an argument is a certain value). | A mock is function implementation whose behaviour is configurable by the test case. Mocks can, for example, verify that function parameters meet requirements set by the test case, return canned values based on programmable criteria (e.g. return failure on the third call or return failure if an argument is a certain value). |
| |
| Mock APIs are typically not coded by hand, as providing a full breadth of programmable behaviour would be prohibitively time consuming. Instead, a mocking framework library is used to implement the the mock. The mocking framework can provide a generic set of tools for customizing mock behaviour, and then the implementor of the mock API merely has to provide glue code to map the API to the mock. | Mock APIs are typically not coded by hand, as providing a full breadth of programmable behaviour would be prohibitively time consuming. Instead, a mocking framework library is used to implement the the mock. The mocking framework can provide a generic set of tools for customizing mock behaviour, and then the implementor of the mock API merely has to provide glue code to map the API to the mock. |
| |
| SysUnit uses [[https://github.com/google/googletest/tree/master/googlemock|GoogleMock]] as its mocking framework. | SysUnit uses [[https://github.com/google/googletest/tree/master/googlemock|GoogleMock]] as its mocking framework. |
| | |
| | ===== Writing a New Test Suite ===== |
| | |
| | SysUnit tests are written in the [[https://github.com/google/googletest/blob/master/googletest/docs/Primer.md|GoogleTest]] framework. You can follow the %%GoogleTest%% documentation to write your test, with the following minor modifications: |
| | * All SysUnit tests must use a test fixture and define test cases with the TEST_F() or TYPED_TEST() macro. Test cases defined with the TEST() macro are not supported. |
| | * The test fixture must derive from SysUnit::%%TestSuite%% (defined in "sysunit/%%TestSuite%%.h") rather than testing::Test |
| | * SysUnit::%%TestSuite%% is a subclass of testing::Test |
| | * SysUnit::%%TestSuite%% defines its own versions of %%SetUp%%() and %%TearDown%%(), and these cannot be overridden. The functionality of these methods has been replaced by %%TestCaseSetUp%%() and %%TestCaseTearDown%%(); your test fixture can override these |
| | |
| | Example code can be found in this sample test case: [[https://github.com/rysto32/sysunit/blob/master/netinet/tcp_lro_sample.gtest.cpp]] |
| | |
| | SysUnit offers some APIs for writing unit tests. These includes generic fake, mock and stub implementations suitable for use in most test cases, as well as other APIs for easily generating useful test data. These APIs are documented at [[SysUnit/APIs]]. |
| |
| ===== Current Status ===== | ===== Current Status ===== |
| ==== Near-Term Goals ==== | ==== Near-Term Goals ==== |
| |
| * Document procedure for writing a new test suite | |
| * Document procedure for adding new mock or fake implementation | |
| * Document current testing APIs | |
| * Integrate sysunit (along with gmock/gtest) into %%FreeBSD%% tree and build infrastructure | * Integrate sysunit (along with gmock/gtest) into %%FreeBSD%% tree and build infrastructure |
| * Integrate sysunit tests with kyua | * Integrate sysunit tests with kyua |
| |