Design and Testing Considerations
Technically, HoldEm now violates encapsulation rules by exposing non-public information. But it provides significant advantages with respect to effective testing. Given the choice between design purity and testing effectiveness, I’ll take modest concessions to design principles any time.
It is possible to take concepts like this too far, however. The more you couple your tests to your production implementations, the harder it becomes to refactor production code. For example, if I want to change the specifics of the createFrame method (perhaps change its name), I can’t do so without also changing test code. On an isolated, small scale, this arrangement is acceptable. On a larger scale, this setup provides a reason for programmers to not refactor. Refactoring represents more work than it used to, since we now have to change tests as well. The inability to refactor at will in turn represents potentially rapid disintegration of code quality.
Right now, I’m not even sure that we can use the NonRenderableFrame class for all of our testing needs. If I remember correctly, there are some Swing characteristics that we won’t be able to test without actually rendering windows onscreen. I guess we’ll find out and deal with it at that time.
Oh, one more thing. We want to ensure that the frame window has some text in the title bar. Let’s add the following assertion to the end of testCreate:
assertEquals("Hold ’Em", frame.getTitle());
The seemingly simplest way to resolve this failing assertion would be to pass along the appropriate title string to the constructor of the JFrame:
JFrame createFrame() { return new JFrame("Hold ’Em"); }
This change doesn’t work. We’re overriding createFrame in the test setUp method. We’d have to supply the same title text there in order to make things pass. That doesn’t seem right. A better solution is to add a line to the initialize method that explicitly sets the title text:
private void initialize() { frame = createFrame(); frame.setTitle("Hold ’Em"); frame.setSize(WIDTH, HEIGHT); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
That change gets the test to pass. As we’re seeing, though, the createFrame method is brittle—we can’t change it without having to also change our tests. Let’s annotate the method so that future developers don’t change or get rid of it without first understanding why it exists:
// used for test overrides. Changing this method may break unit tests! JFrame createFrame() { return new JFrame(); }