Skip to content
This repository has been archived by the owner on Feb 24, 2019. It is now read-only.

0.4 Does It Fit? (unit testing) #16

Closed
emlun opened this issue Sep 18, 2014 · 1 comment
Closed

0.4 Does It Fit? (unit testing) #16

emlun opened this issue Sep 18, 2014 · 1 comment
Assignees
Milestone

Comments

@emlun
Copy link
Collaborator

emlun commented Sep 18, 2014

#0.4 Does It Fit? (unit testing)

There is a file named count_if_followed_by.cpp in the assignment directory:

// .-------------------------------------------------------
// | count_if_followed_by (data, len, a, b);
// |
// | About: Returns the number of occurances of
// | a followed by b in the range [data, data+len).
// ’-------------------------------------------------------
int count_if_followed_by (char const * p, int len, char a, char b) {
  int        count = 0;
  char const * end = p + len;
  while (p != end) {
    if (*p == a && *(p+1) == b)
      count += 1;

    ++p;
  }

  return count;
}

0.4.1 cxxtest; a unit test framework

A unit test framework, such as cxxtest, allows a developer to specify
constraints, and the expected behavior, of an implementation that he/she would
like to test.

These rules are later used to generate unit tests. These unit tests will test
to see that an implementation behaves as it shall (according to the previously
stated specification).

The steps associated with using a unit test framework for C++ typically
includes the following:

  1. Specify the constraints and requirements that you would like to test.
  2. Ask the unit test framework to generate a test runner having semantics
    associated with your specifications.
  3. Compile the test runner into an executable.
  4. Invoke the executable to commence testing.

0.4.1.1 Generating a test runner

There is a file named simple.cxxtest.cpp in the assignment directory.

Asking cxxtest to generate a test runner from the contents of this file can
be accomplished through the following:

$ cp /info/DD2387/labs/lab1/0.4_does_it_fit/simple.cxxtest.cpp .
$ /info/DD2387/labs/cxxtest/cxxtestgen.py --error-printer \
  -o simple_testrunner.cpp simple.cxxtest.cpp

0.4.1.2 Compiling the test runner

Before we can execute our test runner, the test runner itself must be
compiled it into an executable. This includes linking it together with an
object file that contains our implementation.

Create an object file of our implementation:

$ cp /info/DD2387/labs/lab1/0.4_does_it_fit/count_if_followed_by.cpp .
$ g++ -c -o count_if_followed_by.o count_if_followed_by.cpp

Compile our test runner, and link it with the object file:

$ g++ -o simple_test.out -I /info/DD2387/labs/cxxtest/ \
  simple_testrunner.cpp count_if_followed_by.o

The test can be run by invoking ./simple_test.out.

0.4.1.3 Writing a test using_cxxtest_

Note: You may simplify the task of generating, and compiling, test runners by
writing a new rule inside your makefile.

There is an intentional bug in the definition of count_if_followed_by; it
will poten- tially access one element outside the range specified.
Collectively, bugs of this sort is most often referred to as "off-by-one
errors"
.

// expected: result == 0
//  outcome: result == 1 (!!!)

char const data[4] = {’G’,’G’,’X’,’G’};
int const result = count_if_followed_by (data, 3, ’X’, ’G’);

0.4.2 Requirements

  • Submit three (3) different tests to Kattis that test the correct, and
    incorrect, behavior of count_if_followed_by. The tests shall be presented
    during your oral presentation.

0.4.3 Questions

  • Why is it important to test the boundary conditions of an implementation,
    especially in the case of count_if_followed_by?
@emlun
Copy link
Collaborator Author

emlun commented Sep 18, 2014

Tests:

void test_that_it_does_not_look_outside_the_specified_range() {
  char const data[6] = {'G','G','X','G','X','G'};
  int  const result = count_if_followed_by (data, 4, 'G', 'X');
  TS_ASSERT_EQUALS(result, 1);
}

void test_that_it_does_not_crash_when_prefix_is_at_the_end() {
  char const data[6] = {'G','G','X','G','X','G'};
  int  const result = count_if_followed_by (data, 6, 'G', 'X');
  TS_ASSERT_EQUALS(result, 2);
}

void test_that_it_does_not_count_suffix_when_not_preceded_by_prefix() {
  char const data[6] = {'G','A','X','G','X','G'};
  int  const result = count_if_followed_by (data, 6, 'G', 'X');
  TS_ASSERT_EQUALS(result, 1);
}
  • 1b5fa69
    • Errors often happen at the boundaries if you're careless
    • Sometimes errors are more easily exposed at the boundaries even when they
      affect program flow elsewhere as well (and so, testing boundary conditions
      can help expose problems that may not be apparent otherwise).
    • Especially in the case of count_if_followed_by because it does pointer
      arithmetic, which doesn't necessarily cause compile-time errors nor runtime
      crashes.

@emlun emlun closed this as completed Sep 18, 2014
@emlun emlun added this to the Lab1 milestone Sep 18, 2014
@emlun emlun self-assigned this Sep 18, 2014
@emlun emlun added the kattis label Sep 18, 2014
@emlun emlun removed the kattis label Dec 9, 2014
@emlun emlun closed this as completed Dec 9, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant