@@ -9,7 +9,7 @@ AVR, ESP8266, ESP32 and Teensy platforms. The sister AUniter project provides
99command line tools to verify, upload and validate the unit tests. The AUniter
1010tools can be used in a continuous integration system like Jenkins.
1111
12- Version: 1.1.1 (2018-10-18 )
12+ Version: 1.2 (2018-12-01 )
1313
1414[ ![ AUniter Jenkins Badge] ( https://us-central1-xparks2018.cloudfunctions.net/badge?project=AUnit )] ( https://github.com/bxparks/AUniter )
1515
@@ -99,6 +99,9 @@ Here are the features in AUnit which are not available in ArduinoUnit 2.2:
9999* Approximate comparisons:
100100 * ` assertNear() `
101101 * ` asssertNotNear() `
102+ * ` test() ` and ` testing() ` macros support both 1 and 2 arguments
103+ * ` test(testName) ` and ` test(suiteName, testName) `
104+ * ` testing(testName) ` and ` testing(suiteName, testName) `
102105* Test fixtures using the "F" variations of existing macros:
103106 * ` testF() `
104107 * ` testingF() `
@@ -117,8 +120,8 @@ Here are the features in AUnit which are not available in ArduinoUnit 2.2:
117120 * ` TestRunner::include(testClass, name) `
118121 * ` TestRunner::exclude(testClass, name) `
119122* Terse and verbose modes:
120- * ` #include <AUnit.h> ` - terse messages uses less flash memory
121- * ` #include <AUnitVerbose.h> ` - verbose messages uses more flash memory
123+ * ` #include <AUnit.h> ` - terse messages use less flash memory
124+ * ` #include <AUnitVerbose.h> ` - verbose messages use more flash memory
122125* Tested on the following Arduino platforms:
123126 * AVR (8-bit)
124127 * Teensy ARM (32-bit)
@@ -239,21 +242,23 @@ macros are used to create a test:
239242
240243* ` test(name) {...} ` - creates a subclass of ` TestOnce `
241244* ` testing(name) {...} ` - creates a subclass of ` TestAgain `
245+ * ` test(suiteName, name) {...} ` - creates a subclass of ` TestOnce `
246+ * ` testing(suiteName, name) {...} ` - creates a subclass of ` TestAgain `
242247* ` testF(classname, name) {...} ` - creates a subclass of ` classname `
243248* ` testingF(classname, name) {...} ` - creates a subclass of ` classname `
244249
245250The code in ` { } ` following these macros becomes the body of a method in a
246251subclass derived from the base class indicated above. The ` test() ` and ` testF() `
247252macros place the code body into the ` TestOnce::once() ` method. The ` testing() `
248253and ` testingF() ` macros place the code body into the ` TestAgain::again() `
249- method. The name of the subclass is a concatenation of the string ` "test_" ` and
250- the ` name ` for ` test() ` and ` testing() ` , or the concatenation of
251- ` classname ` + ` "_" ` + ` name ` for ` testF() ` and ` testing() ` .
254+ method.
252255
253- The argument to these macros are the name of the test case, and is used to
254- generate a name for the subclass. (The name is available within the test code
255- using the ` Test::getName() ` method). The macros also generate code to create an
256- global instance of the subclass, which are static initialized by C++.
256+ The ` test() ` and ` testing() ` macros support 1 or 2 arguments. The one-argument
257+ version is inherited from ArduinoUnit. The two-argument version is
258+ analogous to the ` TEST() ` macro in GoogleTest, where the ` suiteName ` can
259+ be used to organize multiple tests into a collection of similar tests. The
260+ grouping is purely in the naming scheme of the generated code, there is no
261+ functional relationship between these tests.
257262
258263During static initialization, the constructor of the object adds itself to an
259264internal list. The root of that list is given by ` Test::getRoot() ` . The
@@ -268,11 +273,17 @@ Here is a rough outline of an AUnit unit test sketch:
268273#include < AUnit.h>
269274using namespace aunit ;
270275
271- test (example_test) {
272- ...assertXxx()...
276+ test (example) {
277+ ...
278+ assertXxx(...)
279+ ...
280+ }
281+
282+ test(ExampleTest, example) {
283+ ...
273284}
274285
275- testing(looping_test ) {
286+ testing(looping ) {
276287 ...code...
277288 if (...) {
278289 pass();
@@ -283,6 +294,10 @@ testing(looping_test) {
283294 }
284295}
285296
297+ testing(LoopingTest, looping) {
298+ ...
299+ }
300+
286301class CustomTestOnce: public TestOnce {
287302 protected:
288303 // optional
@@ -348,10 +363,39 @@ void loop() {
348363```
349364
350365***ArduinoUnit Compatibility***: _The basic structure of the unit test is
351- identical to ArduinoUnit. AUnit adds the `testF()` and `testingF`() macros which
366+ identical to ArduinoUnit. AUnit adds the `testF()` and `testingF`() macros,
367+ and the two-argument versions of `test()` and `testing()` which
352368are not available in ArduinoUnit. The `Test` class in ArduinoUnit has been
353369replaced with the `TestAgain` class in AUnit._
354370
371+ ### Generated Class and Instance Names
372+
373+ The arguments to the various `test*()` macros are used to generate the name for
374+ the subclasses of `TestOnce` or `TestAgain`, and generate the names of the
375+ instances of those classes. For reference, here are the rules:
376+
377+ * `test(name)`
378+ * class: `"test_"` + name
379+ * instance: `"test_"` + name + `"_instance"`
380+ * `testing(name)`
381+ * class: `"test_"` + name
382+ * instance: `"test_"` + name + `"_instance"`
383+ * `test(suiteName, name)`
384+ * class: `suiteName` + `"_"` + name
385+ * instance: `suiteName` + `"_"` + name + `"_instance"`
386+ * `testing(suiteName, name)`
387+ * class: `suiteName` + `"_"` + name
388+ * instance: `suiteName` + `"_"` + name + `"_instance"`
389+ * `testF(className, name)`
390+ * class: `className` + `"_"` + name
391+ * instance: `className` + `"_"` + name + `"_instance"`
392+ * `testingF(className, name)`
393+ * class: `className` + `"_"` + name
394+ * instance: `className` + `"_"` + name + `"_instance"`
395+
396+ The instance name is available within the test code using the `Test::getName()`
397+ method.
398+
355399### Binary Assertions
356400
357401Inside the `test()` and `testing()` macros, the following assertions
@@ -1152,6 +1196,41 @@ framework, but let me know if you truly need a timeout of greater than 4m15s).
11521196
11531197*** ArduinoUnit Compatibility*** : _ Only available in AUnit._
11541198
1199+ ## GoogleTest Adapter
1200+
1201+ It may be possible to run simple unit tests written using
1202+ [ Google Test] ( https://github.com/google/googletest/ ) API on an Arduino platform
1203+ by using the
1204+ [ aunit/contrib/gtest.h] ( src/aunit/contrib/gtest.h ) adapter. This
1205+ adapter layer provides a number of macros Google Test macros which map to
1206+ their equivalent macros in AUnit:
1207+
1208+ * ` ASSERT_EQ(e, a) ` - ` assertEqual() `
1209+ * ` ASSERT_NE(e, a) ` - ` assertNotEqual() `
1210+ * ` ASSERT_LT(e, a) ` - ` assertLess() `
1211+ * ` ASSERT_GT(e, a) ` - ` assertMore() `
1212+ * ` ASSERT_LE(e, a) ` - ` assertLessOrEqual() `
1213+ * ` ASSERT_GE(e, a) ` - ` assertMoreOrEqual() `
1214+ * ` ASSERT_STREQ(e, a) ` - ` assertEqual() `
1215+ * ` ASSERT_STRNE(e, a) ` - ` assertNotEqual() `
1216+ * ` ASSERT_STRCASEEQ(e, a) ` - ` assertStringCaseEqual() `
1217+ * ` ASSERT_STRCASENE(e, a) ` - ` assertStringCaseNotEqual() `
1218+ * ` ASSERT_TRUE(x) ` - ` assertTrue() `
1219+ * ` ASSERT_FALSE(x) ` - ` assertFalse() `
1220+
1221+ To use the ` gtest.h ` adapter, include the following headers:
1222+ ``` C++
1223+ #include < AUnit.h>
1224+ #include < aunit/contrib/gtest.h>
1225+ ```
1226+
1227+ or
1228+
1229+ ``` C++
1230+ #include < AUnitVerbose.h>
1231+ #include < aunit/contrib/gtest.h>
1232+ ```
1233+
11551234## Commandline Tools and Continuous Integration
11561235
11571236### AUniter
@@ -1161,29 +1240,33 @@ The command line tools have been moved into the
11611240The ` auniter.sh ` script can compile, upload and validate multiple AUnit tests on
11621241multiple Arduino boards. The script can monitor the serial port and determine if
11631242the unit test passed or failed, and it will print out a summary of all unit
1164- tests at the end.
1165-
1166- Full details are given in the AUniter project, but here are some quick examples
1167- of these tools using the [ AceSegment] ( https://github.com/bxparks/AceSegment )
1168- project.
1169-
1170- The following compiles and verifies the given sketches:
1171- ```
1172- $ AUniter/auniter.sh --verify \
1173- --boards nano,leonardo,esp8266,esp32 AceSegment/tests/*Test
1174- ```
1175-
1176- The following uploads to and runs all the unit tests on an Arduino Nano
1177- (` /dev/ttyUSB0 ` ), then an Arduion Leonardo (` /dev/ttyACM0 ` ):
1178- ```
1179- $ AUniter/auniter.sh --test \
1180- --boards nano:/dev/ttyUSB1,leonardo:/dev/ttyACM0 AceSegment/tests/*Test
1181- ```
1182-
1183- The list of available ports can be found by:
1184- ```
1185- $ AUniter/auniter.sh --list_ports
1186- ```
1243+ tests at the end. Full details are given in the AUniter project, but here are
1244+ some quick examples copied from the ` AUniter/README.md ` file:
1245+
1246+ * ` $ auniter envs `
1247+ * list the environments configured in the ` auniter.ini ` config file
1248+ * ` $ auniter ports `
1249+ * list the available serial ports and devices
1250+ * ` $ auniter verify nano Blink.ino `
1251+ * verify (compile) ` Blink.ino ` using the ` env:nano ` environment
1252+ * ` $ auniter verify nano,esp8266,esp32 Blink.ino `
1253+ * verify ` Blink.ino ` on 3 target environments (` env:nano ` , ` env:esp8266 ` ,
1254+ ` env:esp32 ` )
1255+ * ` $ auniter upload nano:/dev/ttyUSB0 Blink.ino `
1256+ * upload ` Blink.ino ` to the ` env:nano ` target environment connected to
1257+ ` /dev/ttyUSB0 `
1258+ * ` $ auniter test nano:USB0 BlinkTest.ino `
1259+ * compile and upload ` BlinkTest.ino ` using the ` env:nano ` environment,
1260+ upload it to the board at ` /dev/ttyUSB0 ` , then validate the output of the
1261+ [ AUnit] ( https://github.com/bxparks/AUnit ) unit test
1262+ * ` $ auniter test nano:USB0,esp8266:USB1,esp32:USB2 BlinkTest/ ClockTest/ `
1263+ * upload and verify the 2 unit tests (` BlinkTest/BlinkTest.ino ` ,
1264+ ` ClockTest/ClockTest.ino ` ) on 3 target environments (` env:nano ` ,
1265+ ` env:esp8266 ` , ` env:esp32 ` ) located at the 3 respective ports
1266+ (` /dev/ttyUSB0 ` , ` /dev/ttyUSB1 ` , ` /dev/ttyUSB2 ` )
1267+ * ` $ auniter upmon nano:USB0 Blink.ino `
1268+ * upload the ` Blink.ino ` sketch and monitor the serial port using a
1269+ user-configurable terminal program (e.g. ` picocom ` ) on ` /dev/ttyUSB0 `
11871270
11881271### Continuous Integration
11891272
@@ -1269,20 +1352,103 @@ TestAgain TestOnce
12691352::again() ::once()
12701353```
12711354
1272- Placing the `Assertion` and `MetaAssertion` classes inside the `Test` hierarchy
1273- allows those assertion statements to have access to the internal states of the
1274- `Test` instance, which makes certain functions (like the early return upon
1275- delayed failure) slightly easier to implement.
1355+ Normally, deep inheritance hierarchies like this should be avoided. However,
1356+ placing the `Assertion` and `MetaAssertion` classes inside the `Test` hierarchy
1357+ allowed those assertion statements to have access to the internal states of the
1358+ `Test` instance. This made certain features (like the early return upon delayed
1359+ failure) slightly easier to implement. For the most part, the end-users can
1360+ ignore the existence of the `Assertion` and `MetaAssertion` classes and think of
1361+ this as a simple 2-level inheritance tree.
12761362
12771363### Comparing Pointers
12781364
12791365Currently the `assertEqual()` and other `assertXxx()` methods do not support
1280- comparing arbitrary pointers (i.e. `(void*)`. This could change if
1366+ comparing arbitrary pointers (i.e. `(void*)`. This could change if
12811367[Issue #34](https://github.com/bxparks/AUnit/issues/34) is
12821368resolved. In the meantime, a workaround is to cast the pointer to a `uintptr_t`
12831369integer type from `#include <stdint.h>` and then calling `assertEqual()` on the
12841370integer type.
12851371
1372+ ### Testing Private Helper Methods
1373+
1374+ There is a school of throught which says that unit tests should test only the
1375+ publically exposed methods of a class or library. I agree mostly with that
1376+ sentiment, but not rigidly. I think it is sometimes useful to write unit tests
1377+ for `protected` or `private` methods. For example, when creating a chain of
1378+ small helper methods, which build up to larger publically exposed methods, it is
1379+ extremely useful to write unit tests for the helper methods in isolation.
1380+
1381+ Normally those helper methods would be `private` because they are used
1382+ only within that class, and we don't want to expose them to the public API. One
1383+ option is to make them `public` but add a comment in the function to say that it
1384+ is exposed only for testing purposes. This does not seem satisfactory because
1385+ users will tend to ignore such comments if the helper functions are useful.
1386+
1387+ I think a better way is to keep the helper functions `private` but make
1388+ the unit tests a `friend class` of the target class. The syntax for doing this
1389+ can be tricky, it took me a number of attempts to get this right, especially if
1390+ you are also using namespaces for your target class:
1391+
1392+ ```C++
1393+ //------------------- Target.h -------------
1394+
1395+ // Auto-generated test class names.
1396+ class Test_helper;
1397+ class TargetSuite_helper;
1398+ class TargetTest_helper;
1399+
1400+ namespace mylib {
1401+
1402+ class Target {
1403+ public:
1404+ void publicMethod() {
1405+ ...
1406+ int a = helper();
1407+ ...
1408+ }
1409+
1410+ private:
1411+ // Must have the global scope operator '::'
1412+ friend class ::Test_helper;
1413+ friend class ::TargetSuite_helper;
1414+ friend class ::TargetTest_helper;
1415+
1416+ static int helper() {...}
1417+ };
1418+
1419+ }
1420+
1421+ //------------------- TargetTest.ino -------------
1422+
1423+ #include <AUnit.h>
1424+ #include "Target.h"
1425+
1426+ using namespace aunit;
1427+ using namespace mylib;
1428+
1429+ test(helper) {
1430+ assertEqual(1, Target::helper(...));
1431+ }
1432+
1433+ test(TargetSuite, helper) {
1434+ assertEqual(1, Target::helper(...));
1435+ }
1436+
1437+ class TargetTest: public TestOnce {
1438+ ...
1439+ };
1440+
1441+ testF(TargetTest, helper) {
1442+ assertEqual(1, Target::helper(...));
1443+ }
1444+
1445+ ```
1446+
1447+ The tricky part is that in ` Target.h ` you need a forward declaration of the
1448+ various auto-generated AUnit test classes, and within the ` Target ` class itsef,
1449+ the ` friend ` declaration needs to have a global scope ` :: ` specifier before the
1450+ name of the test class.
1451+
12861452## Benchmarks
12871453
12881454AUnit consumes as much as 65% less flash memory than ArduinoUnit 2.2 on an AVR
@@ -1365,6 +1531,8 @@ will incorporate everything, but I will give your ideas serious consideration.
13651531## Authors
13661532
13671533* Created by Brian T. Park (
[email protected] ).
1534+ * The Google Test adapter (` gtest.h ` ) was created by Chris Johnson
1535+ 13681536* The design and syntax of many macros (e.g. ` test() ` , ` assertXxx() ` ) were
13691537 borrowed from the [ ArduinoUnit] ( https://github.com/mmurdoch/arduinounit )
13701538 project to allow AUnit to be almost a drop-in replacement. Many thanks to
0 commit comments