As mentioned before, we consider components as one of the most important extensions provided by mbeddr C. A big advantage of the component-based approach is that the specification of behavior is separated from the implementation. This way, the same interface can be implemented by different components. A particular interesting use case for this feature is the implementation of interfaces specifically for testing purposes as stubs and mocks.
A stub component is a component that implements “dummy” behavior to be used in a test case. Essentially, a stub is just a normal implementation, but it provides counters regarding how often an operation (or port, or the instance in total) has been called. The figure below shows an example. The built-in expression opCallCount is used, together with the in operator, that checks a value for membership in a range.
Mocks are more interesting. They are used to verify that another component behaves as expected. To this end, a mock specifies the expected behavior it wants to see on a provided port. The example below shows a mock component that provides a port the implements PersistenceProvider, which provide the isReady, store and flush operations. The mock specifies that, in a given test case for which the mock is defined, it expects 4 operation calls in total. It specifies a sequence of calls; the first one expects isReady, and returns false. The second expected call is again isReady, but this time we return true. We then expect store to be called, and we check that the data argument is not null. Finally, we expect flush to be called.
A mock component can be instantiated and wired up like any other component. Since a mock is expected to be used in a test case, there is a special new statement that verifies whether the actual behaviour conformed to the expected behaviour. The figure below shows an example. It fails the test case if the mock does not validate.
The mock specification language is a nice example of a DSL that makes sense to be integrated with C. We also reuse C’s expressions in mock expectations. Stubs and mocks also illustrate nicely why a separation between interfaces and the implementation is a useful software engineering paradigm.