Schedule‎ > ‎

14A: Ex. 1 Unit Testing Exercises


The exercises in this HTML file are intended to accompany the lecture notes in 14A: Unit Testing Slides.

Create the Project

Create a new project called TestAddressBook.ino and paste the listing below.  Then, add new files to that project by adding tabs.  You'll be adding three additional files: AddressBookEntry.cpp, AddressBookEntry.h and usableassert.h.  Finally, paste the listings below into those files.

TestAddressBook.ino

#include "AddressBookEntry.h"

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  AddressBookEntry myEntry;
  myEntry.runTests();

}

void loop() {
  // put your main code here, to run repeatedly:

}

AddressBookEntry.cpp

#include <ArduinoSTL.h>
#include "AddressBookEntry.h"
#include "usableassert.h"

using namespace std;

// Modify this function.  Don't look at the rest of the code yet.
bool AddressBookEntry::runTests(void)
{
    Serial.println("Running tests.\n"); Serial.flush();

    // Add tests here

    Serial.println("All tests passed.\n"); Serial.flush();
}

AddressBookEntry::AddressBookEntry()
{
    _title = "";
    _firstName = "";
    _middleName = "";
    _lastName = "";
}

AddressBookEntry::AddressBookEntry(String title, String firstName,
                                   String middleName, String lastName)
{
    _title = title;
    _firstName = firstName;
    _middleName = _middleName;
    _lastName = lastName;
    
}

String AddressBookEntry::title()
{
    return _title;
}

void AddressBookEntry::setTitle(String title)
{
    title = title;
}

String AddressBookEntry::firstName()
{
    return _firstName;
}

void AddressBookEntry::setFirstName(String firstName)
{
    _firstName = firstName;
}

String AddressBookEntry::middleName()
{
    return "Bob"; // Good enough for now
}

void AddressBookEntry::setMiddleName(String middleName)
{
    _middleName = middleName;
}

String AddressBookEntry::lastName()
{
    return _lastName;
}

void AddressBookEntry::setLastName(String lastName)
{
    _lastName = lastName;
}

AddressBookEntry.h

#include <Arduino.h>

class AddressBookEntry {

public:
    AddressBookEntry(void);
    AddressBookEntry(String title, String firstName,
                     String middleName, String lastName);
                     
    String title(void);
    void setTitle(String title);
    
    String firstName(void);
    void setFirstName(String firstName);
    
    String middleName(void);
    void setMiddleName(String middleName);
    
    String lastName(void);
    void setLastName(String lastName);
  
    bool runTests(void);

private:
    String _title;      // Mr.
    String _firstName;  // Barack
    String _middleName; // Hussein
    String _lastName;   // Obama
};

usableassert.h

#define assert(condition) { \
  if (!(condition)) { \
    Serial.print(F(__FILE__)); \
    Serial.print(F(":")); \
    Serial.print(__LINE__); \
    Serial.print(F(": Assertion failed: " #condition)); \
    Serial.flush(); \
    while (1); \
  } \
}

Add Some Tests

In the AddressBookEntry.cpp runTests method, where it says "Add tests here", add the following code:
    AddressBookEntry testEntry("Mr.", "Jim", "Bob", "Murphy");
    assert(testEntry.title() == "Mr.");
    assert(testEntry.firstName() == "Jim");
    assert(testEntry.middleName() == "Bob");
    assert(testEntry.lastName() == "Murphy");
Everything passed.  So we're good, right?  Let's add some more tests just to make sure.
    testEntry.setMiddleName("Phil");
    assert(testEntry.middleName() == "Phil");
Ouch.  We got an assertion failure.  What's wrong?  Hint: look at the middleName() function.  Fix the bug, then run the test again.

Wait, it still isn't working, but now the first assertion for middleName is failing.  Take a look at the constructor and see how _middleName is set.
    _middleName = _middleName;
That clearly isn't right.  Fix that.

Okay, so you think things are working.  Let's try another one.
    AddressBookEntry obamaEntry("Mr.", "Barack", "Hussein", "Obama");
    assert(obamaEntry.title() == "Mr.");
    assert(obamaEntry.firstName() == "Barack");
    assert(obamaEntry.middleName() == "Hussein");
    assert(obamaEntry.lastName() == "Obama");
So far, so good.  But that's not his real title.  Let's try changing it by adding this:
    obamaEntry.setTitle("Honorable");  //title for a former president
    assert(obamaEntry.title() == "Honorable");
What went wrong this time?  You'd think this code was filled with bugs just to see if you're paying attention.  Hmm.  Can you find where the error is and fix it?

Important:  only run some tests at a time or you'll run into Arduino memory constraints.  Comment out the tests that you are not currently working on.

Okay, now that the basics are working, add a few more tests:
  • Add a test for each setter/getter pair to make sure that when you change the value of each field and retrieve the new value, it really changes.
  • Add a test for the default constructor — the one that fills all the fields with empty strings.
  • Before you do the next step,  upload your code to Canvas so you have a copy that you know works - so you can fall back to it if you need to.
  • Add a new field int _age to your AddressBookEntry class.  Add a setter/getter pair of functions to set and retrieve the age.  Change the constructor so that you can enter the age as the last parameter when you create an instance of the AddressBookEntry class. Lastly,  add a unit test for the _age.  That should test the new constructor,  as well as the new set and get age functions.

Submit your code to canvas:  TestAddressBook.ino, AddressBookEntry.cpp and AddressBookEntry.h


 
Comments