C/C++ Samples

From STRIDE Wiki
Jump to navigation Jump to search

Background

The STRIDE Framework provides support for implementation of tests in the native C/C++ used by the device under test. These samples are a collection of source code that demonstrate the techniques for creating and executing target-based (native code) tests using the STRIDE Framework. Once written, these tests are compiled using the device toolchain and are harnessed, via the STRIDE Intercept Module, into one or more applications under test on the device. These tests have the unique advantage of executing in real-time on the device itself, allowing the tests to operate under actual device conditions during test.

Please review the following reference articles before proceeding:

Why would I want to write tests in native code ?

Here are some of the scenarios for which on-target test harnessing is particularly advantageous:

Direct API testing
If you want to validate native APIs by driving the APIs directly, native code is the simplest way to do so. STRIDE provides convenient assertion macros to validate your variable states. API testing can also be combined with native test point tests (using Test Point instrumentation) to provide deeper validation of expected behavior of the units under test.
Unit testing of C objects or C++ classes
The STRIDE native tests execute in the same context as the rest of your code, so it's possible to fully unit test any objects that can be created in your actual application code.
Validation logic that requires sensitive timing thresholds
Sometimes it's only possible to validate tight timing scenarios on-target.
High-volume data processing scenarios
In some cases, the volume of data being processed and validated for a particular test scenario is to large to be easily handled by an off-target harness. In that case, native test units provide a convenient way to write tests that validate that data without shipping the data to the host during testing.

What's more, you might simply prefer to write your test logic in C or C++ (as opposed to perl on the host). If that's the case, we don't discourage you from using a toolset that your more comfortable with - particularly if it enables you to start writing tests without a new language learning curve.

Are there any disadvantages ?

Sure. Most of the disadvantages of native on-target tests concern the device build process. If your device build is particularly slow (on the order of hours or days), then adding and running new tests can become a tedious waiting game. Testing is always well served by shorter build cycles, and on-target tests are particularly sensitive to this.

In some cases, the additional code space requirements of native tests is a concern, but this is also mitigated by ever-increasing device storage capacities. On platforms that support multiple processes (e.g. Linux or Windows), it's possible to bundle tests into one or more separate test process, which further mitigates the code space concern by isolating the test code in one or more separate applications.

Introductory Samples

This is the place to start for on target tests in native code. These samples are meant to serve as a basic overview of many native testing features and techniques. If you are interested in writing tests in C/C++ that run on the device, we recommend building and running these tests, then reviewing the test source code test output.

Test Intro Sample
For C-only environments this is the place to start. These samples are meant to serve as a basic overview of many STRIDE testing features and techniques from a C perspective. If you haven't already done so, we recommend building and running these tests, then reviewing the test source code test output. The process of including this sample as well as running it and publishing results is covered in building a Off-Target TestApp article.
Test Intro Cpp Sample
For C++ environments this is the place to start. The samples provide a basic overview of many STRIDE testing features and techniques from a C++ perspective.

Test Unit Packaging Samples

Test Unit Packaging refers to how functions or methods implementing test cases are packaged into test units. It's possible for different packaging options to coexist, but for consistency and simplicity, we recommend that you decide early on in your test creation cycle what kind of test unit package you will use for your test units and then stick with that for all of your test units. A good overview of the pros and cons for each type is presented here.

If your compiler supports standard C++, the Test Class packaging is preferred as it allows the greatest functionality and flexibility with no added complexity for the simplest use cases.[1] (Note that the Test Class packaging can be used even if the software under test is written in C.)

If you have selected the type of test unit you will be using, we recommend you review and run the corresponding sample. If you are still deciding which type of test unit packaging to use, feel free to peruse all three samples as well as the corresponding documentation.

Test Class Sample (C++ only)
Demonstrates features available when test units are created as C++ classes
Test C Class Sample
Demonstrates how to create and use test units that are C structures
Test Function List Sample
Demonstrates how to create and use test units that are free C functions

Note: each of the three packaging samples include examples that cover basic usage and more advanced reporting techniques (runtimeservices). We recommend for this training that you focus on the basic samples as they cover the important packaging concepts. The runtimeservices examples are relevant only if the built-in reporting techniques are not sufficient for your reporting needs.

Common Testing Features Samples

These samples demonstrate features that are frequently used in common testing scenarios. All developers creating or maintaining tests should be familiar with the techniques shown in these samples.

Pass/Fail Macros

Pass/Fail Macros simplify the task of setting a test case's status to pass or fail. They comprise a set of ASSERTs and EXPECTs that test a condition (e.g. equailty, less than, strings equal, etc.) and set the currently running test to the appropriate pass or fail status. ASSERTs cause the currently executing function to immediately return if fail status is set; EXPECTs do not return.

Test Macros Sample
Demonstrates the use of the Test Code Macros. This sample is implemented using Test Classes (C++ only), but these macros also work in C compilation units.

Advanced Testing Features Samples

The features demonstrated in these samples target specific testing problems.

Test Points

Test points are a unique STRIDE feature that greatly simplifies testing of multi-threaded software as well as single-threaded software that employs callbacks.

Test Point Sample
Demonstrates techniques and syntax for implementing Test Points. With this technique, STRIDE makes it possible to observe and verify activity occurring another thread (e.g. a state machine).

Test Doubles

Test doubles provide a means to intercept function calls so that alternate implementations can be substituted at runtime under the control of your test code. This enables sophisticated mocking, faking, and stubbing.

Test Double Sample
Demonstrates techniques and syntax for implementing Test Doubles. STRIDE's unique implementation makes it possible to dynamically switch in function mocks, stubs, and fakes at runtime. This sample is implemented using Test Classes (C++ only), but the techniques demonstrated work equally well in C compilation units.

File Services

The STRIDE File Services APIs provide a means to perform basic filesystem operations on the host filesystem from test code running on a device. The STRIDE file transfer APIs enable reading/writing of files on the host from the device under test and can be useful for implementing data driven test scenarios (for instance, media file playback).

File Services Sample
Demonstrates techniques and syntax for performing basic tasks using the File Transfer Services API.

Notes

  1. If your C++ compiler supports exceptions and/or namespaces, STRIDE can take advantage of the added capabilities, but these are not required