...
- It has to consist of many separate units. Every unit must have clearly defined interaction with other units.
- Every unit needs to have a clear interface it exposes to other units, so that it can be easily mocked
- Every unit should hold as little state as possible — see below.
- If a unit is hard to test, it probably means it should be split in multiple components. This usually happens when a component starts holding a lot of state and/or has many possible actions and different outcomes — see below.
- Every public interface method declaration should be preceded by the
TEST_VIRTUAL
macro — see this subsection.
...
Sensor dependencies are a different story. Sensor classes are not available at all in testing, so the default constructor won't be able to construct the sensor class unless we provide it one. Therefore, we need to pay special attention when creating a mock for the sensor -- more on this here.
We also need to conditionally include this mock class in the .cpp
implementation, as so:
...
A sensor mock serves as a full substitute for a sensor class (as described here), so its name must be identical to the original class name. The name of the file containing the mock should still start with Mock
and be located under test/
. It also does not extend from the original class, so double-check that their signatures match, as compiling tests won't verify that as is the case with other components.
Code Block | ||
---|---|---|
| ||
#include <gmock/gmock.h> // we don't include the sensor class header class Sensor { // same name as the original class public: Sensor(Wire x, uint8_t){} // whatever the constructor signature for the sensor is. MOCK_METHOD0(bar, void()); MOCK_METHOD1(foo, int(double)); // destructor testing MOCK_METHOD0(__die__, void()); ~Sensor() { __die__(); } } |
...
Read more about the EXPECT_CALL
macro and all of its features just below.
4. In-depth explanation of some testing features and special cases for testing
...
You can also specify what the method should return, or set an argument passed by reference, or anything else it should do -- described here
To just specify the action and not worry about how many times the method is called and how, use ON_CALL
(used in MockStateMachine
for returning mocks).
...
Actually, our great team lead Zack put together a shell script, that executes the whole below procedure (still see the error section). It is located at bin/runUnitTests.sh
(bin
is a sibling of pyxida
) You can run it from bin
or from the top-level folder, but not from anywhere else (for example: pyxida
; bash code for that would require some dark magic not even Zack is certified for).
...