• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Tdd ec-agile2012
 

Tdd ec-agile2012

on

  • 346 views

 

Statistics

Views

Total Views
346
Views on SlideShare
346
Embed Views
0

Actions

Likes
0
Downloads
8
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Tdd ec-agile2012 Tdd ec-agile2012 Presentation Transcript

    • Topics TDD for Embedded C Talk to us on Twitter http://twitter.com/jwgrenning • The why and what of TDD http://twitter.com/basvodde • Embedded adaptation Find us on linkedin.com • Abstracting HW and OS http://www.linkedin.com/in/jwgrenning http://www.linkedin.com/in/basvodde • Mocking the silicon Remind us how we met. • Test-double substitution options http://www.renaissancesoftware.net http:// www.jamesgrenning.com Scaling Lean & Agile Practices for Scaling Lean & Agile • Function pointer substitution Development Development http://www.odd-e.com Thinking and Organizational Tools for Large-Scale Scrum Craig Larman Bas Vodde Large, Multisite, and Offshore Products with Large-Scale Scrum Craig Larman Bas Vodde • Preprocessor substitution • TDD next to an RTOS Come to a full version of James’ TDD for Embedded C October 2012. Phoenix, AZ www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 1 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 2All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com This Work Flow is Designed to Allow Defects Why TDD? What is TDD? Development Test Defects www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 3 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 4All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • The Physics of Debug Later Your program will have Programming (DLP) bugs. And they will surprise you when you Td Tfind T fix find them. Time Mistake made Bug discovery (bug injection) Bug found Bug fixed • As Td increases, Tfind increases dramatically • Tfix is usually short, but can increase with Td www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 5 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 6All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com A Bug’s Life Edsger Dijkstra Those who want really reliable software will discover that they must find means of avoiding the majority of bugs to start with, and as a result, the programming process will become cheaper. If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with. From http://www.softwaretestinghelp.com/bug-life-cycle/ www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 7 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 8All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. basv@odd-e.com
    • Can we Realize Being g Dijkstra’s Dream and ood at c is not T hasing Prevent Defects with echnica bugs l Excelle Test Driven Development? nce www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 9 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 10All Rights Reserved. For use by training attendees. basv@odd-e.com All Rights Reserved. For use by training attendees. basv@odd-e.com Development and Test Work Together Preventing Defects A Complex system that works is invariably found to have evolved from a simple system Development that worked. Test www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 11 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 12All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • The Physics of Test Driven Why is it difficult to sustain? Development T d Tfind T fix Time Mistake Mistake fixed made Mistake Root cause discovery found • When Td approaches zero, Tfind approaches zero TDD: Traditional: • In many cases, bugs are not around long enough to be considered • Steady pace • Spurts bugs. • Speed limits • Fast when no problems! • See: http://www.renaissancesoftware.net/blog/archives/16 • No traffic lights (bugs) • Debugging • Might feel slow!! • Feels fast! But often slow www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 13 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 14All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Sustainability Time developers do not notice nor plan for Traditional Speculate Code Test Debug development Demo and ExerciseTime vs Feels slower Test-driven Spec development ulate Test and Code Debug www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 15 Copyright © 2008-2012 James W. Grenning www.renaissancesoftware.net 16All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX james@renaissancesoftware.net
    • Cheat sheet /* in CheatSheetTest.cpp */ #include "CppUTest/TestHarness.h" /* Declare TestGroup with name CheatSheet */ TEST_GROUP(CheatSheet) { /* declare a setup method for the test group. Optional. */ void setup () CppUTest Quick Intro { /* Set method real_one to stub. Automatically restore in teardown */ UT_PTR_SET(real_one, stub); } /* Declare a teardown method for the test group. Optional */ void teardown() { } }; /* Do not forget semicolumn */ /* In allTest.cpp */ IMPORT_TEST_GROUP(CheatSheet); /* Declare one test within the test group */ TEST(CheatSheet, TestName) /* In main.cpp */ { /* Check two longs are equal */ #include "CppUTest/CommandLineTestRunner.h" LONGS_EQUAL(1, 1); #include "AllTests.h" /* Check a condition */ int main(int ac, char** av) CHECK(true); { return CommandLineTestRunner::RunAllTests(ac, av); /* Check a string */ } STRCMP_EQUAL("HelloWorld", "HelloWorld"); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 17 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 18All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Test Fixture Output Format Data needed in each test. TEST_GROUP(TemplateEngineTest) Run before { each test No news is good news Template aTemplate; TemplatePlaceholderValues replacementValues; ./TestFirst EmailFormatter *emailFormat; . void setup() { OK (1 tests, 1 ran, 1 checks, 0 ignored, 0 filtered out, 0 ms) emailFormatter = createMockFormatter(); aTemplate.setEmailFormat(emailFormat); The data and } void teardown(){ Give precise information when fails destroyFormatter(emailFormatter); ./TestFirst setup / teardown } is also }; Run after TestFirst.cpp:10: error: Failure in TEST(FirstTest, First) make: *** [all] Error 1 sometimes TEST(TemplateEngineTest, templatesWithoutPlaceHoldersDoNotChange) each test expected <1 0x1> called: { but was <0 0x0> test fixture aTemplate.set("Nothing here"); STRCMP_EQUAL("Nothing here", . Errors (1 failures, 1 tests, 1 ran, 1 checks, 0 ignored, 0 filtered out, 0 ms) aTemplate.replaceValues(replacementValues).c_str()); } www.renaissancesoftware.net www.renaissancesoftware.net 49Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 19 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 20All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • More info • CppUTest Github Project page: – http://cpputest.github.com/cpputest/ Adaptation for Embedded • The CppUTest Github repository: Software – https://github.com/cpputest/cpputest • The CppUTest Man page: – http://www.cpputest.org/ www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 21 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 22All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com What are the special What is special about embedded challenges you have over a • Concurrent HW development non-embedded developer? • HW bottleneck • Cross compilation • Limited memory and IO • Target debug • Architecture www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning www.renaissancesoftware.net 23 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 24All Rights Reserved. For use by training attendees. james@renaissancesoftware.net All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Hardware is Scarce! • It does not exist. • It is being used by someone else. • It has bugs of its own. www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 25 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 26All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 27 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 28All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. basv@odd-e.com
    • Minimize DoH! Debug on Copyright Fox Broadcasting. Used under fair use. Hardware www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 29 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 30All Rights Reserved. For use by training attendees. basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Why Use Your Development System How to Use Your Development for a Test Bed? System for a Test Bed? • Waiting for hardware. • Multi-targeted code. • Waiting for restart. • Must make code portable • Waiting for downloads. • Must beware of hardware and OS dependencies. • Waiting for long compiles. • Object Oriented approach to Dependency • Debugging on the target. Management. • Target has bugs. • (Re)Configuring the lab Avoid wasteful practices www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 31 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 32All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • But There are Risks with TDD Adaptation for Embedded Development System Tests Development • Architecture differences Stage 1 Stage 2 Stage 3 Stage 4 Stage 5 – Word size – Big-endian Little-endian – Alignment Write a Test Compile Run Tests Run Tests Acceptance Make it Pass for Target in the Eval in Target Tests • Compiler differences Refactor Processor Hardware Hardware • Library differences • Execution differences More Frequent Less Frequent www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 33 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 34All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com TDD Adaptation for Embedded Continuous Integration - Embedded Development 3. CIS notices changes, refreshes its local copy, builds and runs host 2. Developer Stage 1 Stage 2 Stage 3 Stage 4 Stage 5 checks in work Source Code Continuous Integration Test Management regularly. Repository Server System 4. After successful host build/test, CIS Write a Test Compile Run Tests Run Tests Acceptance builds and hands Make it Pass for Target in the Eval in Target Tests images to TMS to deploy to Refactor Processor Hardware Hardware simulator, eval/ reference boards 1. Developer has or target system. all unit tests Eval/Reference More Frequent Less Frequent System Developer Simulator Target System Workstation See : http://renaissancesoftware.net/files/articles/ProgressBeforeHardware.pdf The SCR, CIS and TMS are not necessarily separate hardware systems. www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 35 Copyright © 2008-2012 James W. Grenning 35 james@renaissancesoftware.netAll Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Problems Found at Appropriate Stage Stage Problems Likely to Find in Stage 1 Logic, design, modularity, interface, boundary conditions 2 Compiler compatibility (language features) Library compatibility (header files, declarations) Hardware and OS Abstraction 3 Processor executions problems (compiler and library bugs) Portability problems (word size, alignment, endian) 4 Ditto stage 3 Hardware integration problems Misunderstood hardware specifications 5 Ditto stage 4 Misunderstood feature specification www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 37 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 38All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Separation of Responsibilities Light Scheduler Design • Every minute, the RTOS wakes up Admin Console Light Scheduler • Program to Admin Console Light Scheduler the Light +ScheduleTurnOn() Interfaces + ScheduleTurnOn() +RemoveSchedule() + RemoveSchedule() Scheduler. +WakeUp() <<anonymous callback>> • Separate interface +WakeUp() <<anonymous callback>> • If it is time for and implementation as separate entities. <<interface>> <<interface>> Light Controller Time Service one of the lights to + On(id) + GetTime() Light Controller + On(id) Time Service + GetTime() be controlled, the + Off(id) + SetPeriodicAlarm() • This design has + Off(id) + SetPeriodicAlarm() LightController is good separation of <<implements>> <<implements>> told to turn on/off Hardware RTOS responsibilities Model 42 RTOS Light Controller Time Service the light. Model 42 Hardware RTOS www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 39 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 40All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • LightScheduler Test Fixture Design Testing the Scheduler Light TEST(LightScheduler, light_not_changed_at_the_wrong_time) • Use the real Scheduler Light Scheduler { Test collaborators if + ScheduleTurnOn() LightScheduler_ScheduleTurnOn(3, EVERYDAY, 1200); FakeTimeService_SetMinute(1199); + RemoveSchedule() you can. +wakeUp() LightScheduler_Wakeup(); LONGS_EQUAL(NO_LIGHT_ID, LightControllerSpy_GetLastId()); • Use fakes when LONGS_EQUAL(LIGHT_STATE_UNKNOWN, LightControllerSpy_GetLastState()); } you must. <<interface>> Light Controller <<interface>> Time Service + On(id) + GetTime() TEST(LightScheduler, light_changed_at_the_right_time) + Off(id) + SetPeriodicAlarm() { LightScheduler_ScheduleTurnOn(3, EVERYDAY, 1200); FakeTimeService_SetMinute(1200); <<implements>> <<implements>> LightScheduler_Wakeup(); Light Controller Fake LONGS_EQUAL(3, LightControllerSpy_GetLastId()); Spy Time Service LONGS_EQUAL(LIGHT_ON, LightControllerSpy_GetLastState()); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 41 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 42All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Light Scheduler Test List A Complex system that Light Scheduler Tests works is invariably Lights are not changed at initialization found to have evolved Time is wrong, day is wrong, no lights are changed Day is right, time is wrong, no lights are changed from a simple system Day is wrong, time is right, no lights are changed Day is right, time is right, the right light is turned on Day is right, time is right, the right light is turned off that worked. Schedule every day Schedule a specific day Schedule all weekdays Schedule weekend days Remove scheduled event Remove non-existent event Multiple scheduled events at the same time Multiple scheduled events for the same light Remove non scheduled light schedule Schedule the maximum supported number of events (128) Schedule too many events www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 43 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 44All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Partial Skeleton Let’s Your Try the Copy/Paste THINK Design and Test Ideas Early TEST(LightScheduler, light_not_changed_at_the_wrong_time) { LightScheduler_ScheduleTurnOn(3, EVERYDAY, 1200); TransitionClockTo(SUNDAY, 1199); ExpectLightsUnchanged(); } TEST(LightScheduler, light_changed_at_the_right_time) { LightScheduler_ScheduleTurnOn(3, EVERYDAY, 1200); TransitionClockTo(SUNDAY, 1200); ExpectLightOn(3); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 45 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 46All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Replacing collaborators • Linker-stubbing Test-Double Substitution • Function pointer • Pre-processor Options www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 47 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 48All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Linker Stubbing #include "sqlite3.h" int sqlite3_open(const char *filename, sqlite3 **ppDb) { FAIL("sqlite3_open"); return 0; } Linker Substitution int sqlite3_step(sqlite3_stmt*) { FAIL("sqlite3_step"); return 0; } Don’t link the real library. int sqlite3_reset(sqlite3_stmt *pStmt) { Instead provide a fake FAIL("sqlite3_reset"); return 0; that does something } sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*) useful for the test { FAIL("sqlite3_last_insert_rowid"); return 0; } int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64) { FAIL("sqlite3_bind_int64"); return 0; } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 49 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 50All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Use linker stubs across subsystems Interface TinyXML Function Pointer Substitution • Use linker stubs on other Sqlite subsystems • Linker stubs requires no change in code! Engine dbus ✔ fzshelltext putty www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 51 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 52All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Reasons to Use Function Pointers for Example Usage - Printed Output Test-Doubles • When you already use function pointers for other • Logs and printed output are helpful for checking purposes (you have a built-in test hook!) program correctness and debugging – Swappable device drivers • But... – Swappable implementations – They require that you look at the output. • You need the production implementation in the test – They doom you to a lifetime of manually verified tests build, and you must substitute a test double in the • So... same test build – Design your code so that printed output can be captured – printf and verified in your unit tests • You don’t want to have too many test builds due to using link-time substitution www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 53 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 54All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Manual/Tedious/Error Prone Function Pointer - Runtime Output Inspection Substitution • Sometimes we want to use the real function. • Sometimes we want to use a test version. • Define a function pointer that has the same declaration as the function to override, in this case printf() #ifndef D_FormatOutput_H #define D_FormatOutput_H extern int (*FormatOutput)(const char *, ...); #endif // D_FormatOutput_H www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 55 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 56All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • By default, FormatOutput points to the Production Code printf Before: void someProductionCode() { printf(“hello %sn”, “world”); //FormatOutput.c } #include "FormatOutput.h" #include <stdio.h> After: int (*FormatOutput)(const char* format, ...) = printf; #include "FormatOutput.h" . . . . . void someProductionCode() { FormatOutput(“hello %sn”, “world”); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 57 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 58All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Runtime Substitution UT_PTR_SET Test setup and teardown • We can override the function by assigning the test • CppUTest has a mechanism for overriding and version of the function during setup restoring pointers that must be restored after each • Don’t forget to restore the original test. • How should I do this more safely? • UT_PTR_SET() assigns the pointer and restores the original function pointer after teardown() void setup() { void setup() FormatOutput = FormatOutputSpy; { } UT_PTR_SET(FormatOutput, FormatOutputSpy); } void teardown() { void teardown() FormatOutput = printf; { } } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 59 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 60All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Sometime we Write Tests for Test Code Spy Overflow We must be able to trust the spy. Tests are documentation! TEST(FormatOutput, ATestThatPrintsThings) TEST(FormatOutput, LimitTheOutputBufferSize) { { FormatOutputSpy_Create(20); FormatOutputSpy_Create(4); FormatOutput("Hello, Worldn"); FormatOutput("Hello, Worldn"); STRCMP_EQUAL("Hello, Worldn", STRCMP_EQUAL("Hell", FormatOutputSpy_GetOutput()); FormatOutputSpy_GetOutput()); } } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 61 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 62All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com More Checking on our Spy Spying on the Output TEST(CircularBufferPrint, PrintNotYetWrappedOrFull) { CircularBuffer_Put(buffer, 10); TEST(FormatOutput, PrintMultipleTimes) CircularBuffer_Put(buffer, 20); { CircularBuffer_Put(buffer, 30); FormatOutputSpy_Create(25); CircularBuffer_Print(buffer); FormatOutput("Hello"); FormatOutput(", Worldn"); expectedOutput = "Circular buffer content:n<10, 20, 30>n"; STRCMP_EQUAL("Hello, Worldn", STRCMP_EQUAL(expectedOutput, FormatOutputSpy_GetOutput()); FormatOutputSpy_GetOutput()); } } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 63 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 64All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Test Fixture TEST_GROUP(CircularBufferPrint) { CircularBuffer buffer; const char * expectedOutput; const char * actualOutput; Preprocessor Substitution void setup() { UT_PTR_SET(FormatOutput, FormatOutputSpy); FormatOutputSpy_Create(100); buffer = CircularBuffer_Create(10); } void teardown() { CircularBuffer_Destroy(buffer); FormatOutputSpy_Destroy(); } }; www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 65 Copyright © 2008-2012 James W. Grenning www.renaissancesoftware.net 66All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX james@renaissancesoftware.net Preprocessor Substitution Preprocessor Substitution Variants • Is the least desirable form of substitution • Header file test double • Though necessary when – Change the include path during test builds – Header files won’t compile off-target • Force includes – Header files have are the start to a massive dependency – Force in a header file that substitutes problem chain dependencies – A direct function call API cannot be changed and you • Command line definition need to override the direct call and use the direct call in – Override a symbol one at a time the implementation of the fake e.g. malloc(), free() www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 67 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 68All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Processor Dependent Header File Adjust the Include Path So the #include Test-Double is Found First #if defined(_ACME_X42) typedef unsigned int Uint_32; typedef unsigned short Uint_16; #ifndef ACMETYPES_H_ typedef unsigned char Uint_8; #define ACMETYPES_H_ typedef int Int_32; #include <stdint.h> typedef short Int_16; typedef char Int_8; typedef uint32_t Uint_32; #elif defined(_ACME_A12) typedef uint16_t Uint_16; typedef unsigned long Uint_32; typedef uint8_t Uint_8; typedef unsigned int Uint_16; typedef unsigned char Uint_8; typedef int32_t Int_32; typedef long Int_32; typedef int16_t Int_16; typedef int Int_16; typedef int8_t Int_8; typedef char Int_8; #else #endif /* ACMETYPES_H_ */ #error <acmetypes.h> is not supported for this environment #endif Read about it at http://www.renaissancesoftware.net/blog/archives/231 www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 69 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 70All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Just to be Sure, Add this Test Ideally • Use a portable types file, rather than vendor dependent file TEST(acmetypes, checkIntSizes) • Limit the areas of your code that depend on problem { LONGS_EQUAL(1, sizeof(Uint_8)); vendor code LONGS_EQUAL(1, sizeof(Int_8)); LONGS_EQUAL(2, sizeof(Uint_16)); LONGS_EQUAL(2, sizeof(Int_16)); LONGS_EQUAL(4, sizeof(Uint_32)); LONGS_EQUAL(4, sizeof(Int_32)); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 71 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 72All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • See the C that is NOT C Force Include //OffTargetDefines.h /* Chip Vendor Specific Header File */ ... extern cregister volatile unsigned int AMR; /* Address Mode Register */ #define cregister extern cregister volatile unsigned int CSR; /* Control Status Register */ #define interrupt extern cregister volatile unsigned int IFR; /* Interrupt Flag Register */ ... extern cregister volatile unsigned int ISR; /* Interrupt Set Register */ extern cregister volatile unsigned int ICR; /* Interrupt Clear Register */ extern cregister volatile unsigned int IER; /* Interrupt Enable Register */ extern cregister volatile unsigned int ISTP; /* Interrupt Service Tbl Ptr */ extern cregister volatile unsigned int IRP; /* Interrupt Return Pointer */ extern cregister volatile unsigned int NRP; /* Non-maskable Int Return Ptr*/ extern cregister volatile unsigned int IN; /* General Purpose Input Reg */ extern cregister volatile unsigned int OUT; /* General Purpose Output Reg */ ... Read about it at http://www.renaissancesoftware.net/blog/archives/249 www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 73 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 74All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Registers Become Global Variables Ideally // FakeRegisters.c volatile unsigned int AMR; • You should limit areas of your code that are vendor volatile unsigned int volatile unsigned int CSR; IFR; specific volatile unsigned int volatile unsigned int ISR; ICR; • Make a Hardware Abstraction Layer volatile unsigned int IER; volatile unsigned int ISTP; volatile unsigned int IRP; volatile unsigned int NRP; volatile unsigned int IN; volatile unsigned int OUT; www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 75 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 76All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Undefine the Override So the Original Command Line Definition Can be Used #undef malloc • Compilers all preprocessor symbols to be defined on #undef free the command line • These gcc command line options changes all void * cpputest_malloc(size_t size) { occurrences of malloc() to cpputest_malloc() and // do the malloc/free book keeping free() to cpputest_free() return malloc(size); -Dmalloc=cpputest_malloc } -Dfree=cpputest_free void cpputest_free(void * mem) { // do the malloc/free book keeping return free(mem); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 77 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 78All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Problem - asm What is an AsmSpy? The legacy code has asm instructions that won’t compile off- target TEST(AsmSpy, captures_asm_text) { Solution - 1 AsmSpy("NOP"); AsmSpy("GLOP"); Make asm go away using forced include AsmSpy("SLOP"); STRCMP_EQUAL("NOP;GLOP;SLOP;", AsmSpy_Debrief()); } Solution - 2 Introduce an AsmSpy to capture the instruction stream and check it in a test case Read more: http://www.renaissancesoftware.net/blog/archives/136 http://www.renaissancesoftware.net/blog/archives/143 • See http://www.renaissancesoftware.net/blog/archives/136 www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 79 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 80All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Force Include AsmSpy.h Problem - #pragma The legacy code has #pragma instructions that won’t #ifndef D_AsmSpy_H compile off-target #define D_AsmSpy_H Solution #define asm AsmSpy Adjust the compiler settings to ignore unknown #pragmas void AsmSpy_Create(int size); void AsmSpy_Destroy(void); void AsmSpy(const char *); const char * AsmSpy_Debrief(void); #endif www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 81 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 82All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Test-double types • Exploding stubs • Dynamic Types of Test-doubles • Recording - Mock • Generic www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 83 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 84All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Exploding stubs Dynamic stub stubSqlite.cpp sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*) sqlite3_int64 sqlite3_last_insert_rowid(sqlite3* lite) { { FAIL("sqlite3_last_insert_rowid"); if (sqlite3_last_insert_rowid_stub) } return 0; return sqlite3_last_insert_rowid_stub(lite); “Sensible default” return 0; } stubSqlite.h extern sqlite3_int64 (*sqlite3_last_insert_rowid_stub)(sqlite3*); Easy and you know when it is used. Delays more implementation... www.renaissancesoftware.net www.renaissancesoftware.net 14Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 85 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 86All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Recording ... mock Generic stub stubSqlite.cpp Dynamic when set sqlite3_int64 sqlite3_last_insert_rowid(sqlite3* lite) Mock by default { mock("Sqlite").actualCall("sqlite3_last_insert_rowid").withParameter("lite", lite); stubSqlite.cpp if (mock("Sqlite").hasReturnValue()) sqlite3_int64 sqlite3_last_insert_rowid(sqlite3* lite) return (sqlite3_int64) mock("Sqlite").returnValue().getIntValue(); { if (sqlite3_last_insert_rowid_stub) return 0; return sqlite3_last_insert_rowid_stub(lite); } mock("Sqlite").actualCall("sqlite3_last_insert_rowid").withParameter("lite", lite); if (mock("Sqlite").hasReturnValue()) return (sqlite3_int64) mock("Sqlite").returnValue().getIntValue(); testUsingSQL.cpp return 0; TEST(ProgramUsingSQLite, InserRowID) } { mock("Sqlite").expectOneCall("sqlite3_last_insert_rowid").withParameter("lite", lite) .andReturnValue(0); ... mock("Sqlite").checkExpectations(); mock("Sqlite").clear(); } With a “sensible default” www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 87 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 88All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • CppUMock MockPlugin MockPlugin does checking expectations and cleanup Mocking the Silicon automatically Install it! main.cpp int main(int ac, char** av) { MockSupportPlugin plugin; TestRegistry::getCurrentRegistry()->installPlugin(&plugin); return CommandLineTestRunner::RunAllTests(ac, av); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 89 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 90All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Message Flow for Why a Mock Object? Flash Memory Block Erase with Error • Problem - Complex collaborator interactions cannot FlashDriver FlashDevice be captured with a simple spy. Flash_Program(offset, data) • Solution - Mock Object IOWrite(CommandRegister, 0x40) – A Mock Object is a Test Double that verifies that the code IOWrite(offset, data) being tested interacts with its collaborator properly. – The test tells the mock IORead(StatusRegister) Repeats while b7 == 0 – The expected calls b7 == 0 – In the expected order IORead(StatusRegister) – What to return. b7 == 1, other bits == 0 IORead(offset) FlashSuccess data www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 91 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 92All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Flash Program Flow Chart Flash Driver Test Fixture How Many Tests are Needed? FlashDriver + Program(addr, data) FlashDriverTest + ProtectBlock(block) Start + EraseBlock(block) How do //etc Program Command b3 == 0 NO Vpp Error you test Write 0x40 to 0x0 YES these <<interface>> errors in IO Write data to address b4 == 0 NO Program Error the target? + Read(addr) : data + Write(addr, data) Wait for ready loop YES Read status <<implements>> register Protected Block b1 == 0 NO Error MockIO <<implementation>> YES + Expect_Read(addr, data) <<hardware>> IO b7 == 1 NO + Expect_Write(addr, data) Clear status Start/Stop Write 0xFF to 0x0 YES www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 93 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 94All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Flash Driver Test Mock Flash Write / Read TEST(Flash, ProgramSucceedsReadyImmediately) void IOWrite(ioAddress_t addr, ioData_t value) { { int result = 0; mock_scope_c("IO")->actualCall("IOWrite")->withIntParameters("addr", addr)->withIntParameters("value", value); mock("IO").strictOrder(); } mock("IO").expectOneCall("IOWrite").withParameter("addr", CommandRegister).withParameter("value", 0x40); mock("IO").expectOneCall("IOWrite").withParameter("addr", (int)0x1000).withParameter("value", 0xBEEF); ioData_t IORead(ioAddress_t addr) mock("IO").expectOneCall("IORead").withParameter("addr", (int)0).andReturnValue(1<<7); { mock("IO").expectOneCall("IORead").withParameter("addr", (int)0x1000).andReturnValue(0xBEEF); mock_scope_c("IO")->actualCall("IORead")->withIntParameters("addr", addr); result = Flash_Program(0x1000, 0xBEEF); return mock_scope_c("IO")->returnValue().value.intValue; } LONGS_EQUAL(0, result); mock().checkExpectations(); mock().clear(); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 95 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 96All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • What do the Tests Mean? Minimize DoH! Debug • Vendor’s driver did not pass my tests • Undocumented operations (resets) were added in silicon vendor’s solution. • My driver functions met the spec, but may have encountered integration problems – Were the extra resets really needed? on Copyright Fox Broadcasting. Used under fair use. Hardware www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 97 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 98All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Choices When Faking the OS • For new code, you might choose to create an OS abstraction layer. TDD Next to an RTOS • For existing code, or where the layer is not desired, you can create an RTOS test double Intro to the Fake Function Framework www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning www.renaissancesoftware.net 99 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 100All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX james@renaissancesoftware.net All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • How Do I Test OS Dependent Code The ISR Has to Satisfy the Request Like This? int MessageProcessor_WaitForMessage(char * buffer, size_t length) { MessageProcessor SerialDriver Semaphore INT8U error = 0; SerialInterrupt_WaitForString(buffer, length, int_sync); WaitForMessage(buffer, length) OSSemPend(int_sync, 1000, &error); WaitForString(buffer, length, semophore) return error == OS_ERR_NONE; } Pend(semaphore) Message Interrupt is Processor is I may just fake out But that may not be collecting characters blocked, waiting for its WaitForMessage() an option in legacy code Post(semaphore) characters and manually test the Where OS primitives are return OS dependent code. used more liberally. www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 101 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 102All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com • But that may not be an option in legacy code where Let the Fake Doused more liberally. Would OS primitives are the Work That Fakes are Created With the Fake Happen Concurrently Function Framework #ifndef D_uCosII_TestDouble_H MessageProcessor SerialDriverSpy SemaphoreFake #define D_uCosII_TestDouble_HWaitForMessage(buffer, length) WaitForString(buffer, length, semophore) #include "fff2.h" extern "C" { Pend(semaphore) #include "ucos_ii.h" } The Semaphore Test-Double FAKE_VALUE_FUNCTION(OS_EVENT *, OSSemCreate, INT16U) fills the buffer and returns FAKE_VOID_FUNCTION(OSSemPend, OS_EVENT *, INT32U, return INT8U *) www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 103 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 104All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Basic fff Features The Test Case TEST(uCosII_TestDouble, OSSemPend_basics) TEST(MessageProcessor, WaitForMessage_succeeds) { { OS_EVENT event; fakeInput = "sched lightOn 5 Monday 20:00"; INT8U error; CHECK_TRUE( OSSemPend(&event, 0, &error); MessageProcessor_WaitForMessage( LONGS_EQUAL(1, OSSemPend_fake.call_count); (char*)&receiveBuffer, sizeof(buffer)) POINTERS_EQUAL(&event, OSSemPend_fake.arg0_val); ); LONGS_EQUAL(0, OSSemPend_fake.arg1_val); LONGS_EQUAL(1, OSSemPend_fake.call_count); POINTERS_EQUAL(&error, OSSemPend_fake.arg2_val); STRCMP_EQUAL(fakeInput, receiveBuffer); POINTERS_EQUAL(&event, OSSemPend_fake.arg0_history[0]); } LONGS_EQUAL(0, OSSemPend_fake.arg1_history[0]); } www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 105 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 106All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com Its Custom Implementation Satisfies Its Setup and Teardown the Scenario TEST_GROUP(MessageProcessor) static const char * fakeInput; { static char receiveBuffer[100]; void setup() void MyOSSemPend(OS_EVENT *event, INT32U timeout, { INT8U *error) OSSemPend_reset(); { OSSemPend_fake.custom_fake = MyOSSemPend; memcpy(receiveBuffer, fakeInput, strlen(fakeInput)); MessageProcessor_Create(); *error = OS_ERR_NONE; } } void teardown() { MessageProcessor_Destroy(); } }; www.renaissancesoftware.net www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 107 Copyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 108All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com
    • Talk to us on Twitter http://twitter.com/jwgrenning Practices for http://twitter.com/basvodde Scaling Lean & Agile Scaling Lean & Agile Development Development Find us on linkedin.com Thinking and Organizational Tools for Large-Scale Scrum Large, Multisite, and Offshore Products with Large-Scale Scrum http://www.linkedin.com/in/jwgrenning Craig Larman Bas Vodde Craig Larman Bas Vodde http://www.linkedin.com/in/basvodde Remind us how we met. http://www.renaissancesoftware.net http:// www.jamesgrenning.com http://www.odd-e.com www.renaissancesoftware.netCopyright © 2008-2012 James W. Grenning james@renaissancesoftware.net 109All Rights Reserved. For use by training attendees. Agile 2012, Grapevine, TX basv@odd-e.com