I was told that unit test is a powerful tool for progamming. If I am
writing a GUI code, is it possible to still using unit test?
I have an approach based on some stuff I read in Michael Feather's
book. It is not as developed as what Andrew posted (for example, I
don't have a clever name for it), but it works for me.
I've been doing MFC programming, so I'll give my example there,
although it's just an example. In MFC, there's a class called CDC,
which is the C (language) device context. It has a bunch of primitive
drawing methods like:
CPoint MoveTo(int x, int y);
Now I'm writing a class C that does a bunch of drawing, so it winds up
calling these. It has a method OnDraw that takes a CDC* and does the
drawing (in turn calling a bunch of other methods). This is the
method I want to test.
So basically, I created a class called DCInterface, which looks like
this:
class DCInterface {
public:
virtual CPoint MoveTo(int x, int y) = 0;
/* etc. */
};
Then, I created a class CDCWrapper that calls the actual one:
class CDCWrapper : public DCInterface {
private:
CDC* pDC;
public:
explicit CDCWrapper(CDC* p) : pDC(p) {}
CPoint MoveTo(int x, int y) { return pDC->MoveTo(x, y); }
/* etc. */
Then I refactor my code for class C to use a DCInterface instead of a
CDC. (The OnDraw method stays, since the MFC framework calls it, but
now it just creates a CDCWrapper and forwards on to the wrapped
version of OnDraw.)
So far, everything is just setup for unit testing.
Now, here's the cool part. I created a TestDC class that implements
all of the functionality by storing a string with messages like
"MoveTo(5, 6) called.\n";
So to do unit tests, I set everything up with my TestDC class, and the
output is a string (instead of drawing something on the screen). I
can then do all my assertions that the appropriate series of draw
operations were called, based on looking at the output string.
This obviously doesn't do everything, but it lets me unit test some
fairly complex graphics routines.
More generally, you can pull out a wrapper that has virtual copies of
the library interface. Create an "real" implementation class that
just delegates to the library, then create a separate "test"
implementation class that stores things to a string (or some other
structure that's easy to use in unit tests).
There's a fair amount of work to create the wrappers in the first
place - I took the approach of "only wrap functions you actually use,"
but that's a one-time cost and then you can reuse it for your unit
testing.
Michael
Thanks a lot for your reply. What I understand is that I write a class
to simulate the behavior of the GUI class. The new class uses some
information to substitute the graphical and interactive operations. Is