Work with the same partner(s) you worked with for the first books assignment.
Relevant files
For your convenience, here are the files you'll need for this assignment.
Goals
- Think about design considerations when creating an interface for a books data source.
- Understand the benefits of creating such an interface.
- Create unit tests for the data source interface using the
unittest module
(also known as PyUnit).
- Think about how to create unit test collections that cover a wide range of inputs, contexts,
and possible errors.
Test-driven development
One purpose of this and the next couple assignments is to give you an introduction to
test-driven development (TDD).
Roughly, the process goes like this:
- You start with a class whose interfaces have been written and agreed upon. (For our
purposes, an interface will refer to a method signature plus the descriptive
comment that goes with it.)
- You write a collection of unit tests
to thoroughly test the agreed-upon interfaces. You do this before implementing
the interfaces.
- You implement the interfaces, using the unit tests to help you debug and to give you
a way to determine whether you're done with the implementation.
For us, the class will be called BooksDataSource, and its purpose will
be to provide Python programmers with convenient access to the data in our books dataset.
The trick to writing good unit test suites is to think deeply about the many ways your
interfaces might be called. Your tests should, for example, test typical cases,
weird cases, and illegal cases. (For a really simple example, a unit test suite for a square-root function
ought to include attempts to compute the square-roots of positive integers, positive non-integers,
negative numbers, and zero, and depending on the
language and the completeness of the interface specification, maybe the square-root of "moose"
or other non-numerical input.) You
should think hard about the mistakes programmers can make, the bad data users can generate,
and the ways malicious programmers might try to exploit errors or omissions in your code.
Your job
- Take a look at these new books.csv and
authors.csv data files to get a feel for the kind of data
we're thinking about for this assignment.
- Read this
interface for a BooksDataSource class carefully.
Think about what features this specification supports and does not support, and collect your
questions about the interface's design and its Python details. You will not be allowed
to change this interface, so get to know it.
- Create a new directory called booksdatasource in your repository.
Save a copy of booksdatasource.py
in booksdatasource, and leave it untouched for the remainder of this assignment.
- Create a new Python file called booksdatasourcetest.py, with a class called
BooksDataSourceTest inheriting from unittest.TestCase. You may use
primecheckertests.py as a template to get started.
- Implement a thorough collection of unit tests for the non-constructor methods in BooksDataSource.
The goal of these tests is to provide as wide a range of unit tests as you can think of. Don't
repeat yourself (you probably wouldn't need to test both square_root(3.0) and square_root(5.0)),
but also don't be shy about writing lots of tests. Effectively probing the potential
vulnerabilities of an interface usually takes lots of little tests.
- Your tests may involve using a variety of small CSV files of your own creation, since,
for example, it would be easier to test the sorting of a list of three books than a list
of 45 books. Save your data files, if any, in the booksdatasource directory along with your
.py files.
- Put a Makefile in your booksdatasource directory, and include in it a test target
so you (and I, and the grader) can just type "make test" in your booksdatasource directory to
run your unit tests.
- Once you're happy with your unit tests, tag your repo with the tag booksdatasource
and push your work (and the tag, which you may recall requires a special push command) up to GitHub.
A few notes
- I know I already said this up above, but let me say it again, in boldface:
You may not change BooksDataSource in any way.
(The graders and I will test this by using the Unix command diff, by the way.)
Later, when it comes time to implement the methods in the BooksDataSource
class, you'll be able to add new methods as needed, but even then you
may not change BooksDataSource's original method signatures.
Adhering to an agreed-upon specification without changing it is an important skill, not
least because the tests you write before implementing the interface
will assume that the method signatures remain as agreed.
- Writing tests ahead of time feels weird, because you can't exactly test your tests.
Embrace the weirdness, and recognize that it takes skilled test-writers a lot of practice
to get tests right from the beginning.
- To keep things (temporarily) simple, we're using CSV file formats for the books
and authors assuming that no book ever has more than one author. We'll fix that problem
next week.
Good luck
Start early, ask lots of questions, and have fun!