I'm very familiar with xUnit frameworks and I try to implement unit tests on every project I start. Somewhere along the way, I realize that I'm writing the same tests over and over again, and then I run into a really difficult to test method or a test involving remote resources, and then I give up for a while. I end up coming back eagerly whenever I can to test simple things, but as soon as I run into harder things to test, I run for the hills with my tail between my legs.
Let's throw in some examples.
Long flow of things to do in a method. (How do I test this? Do I just make sure that the code's being called by stubbing things out? How should I rewrite the code to facilitate easier testing?)
public void doSomething() { Object1 value1 = doSomething1(this.getName()); if (value1.isError()) { sendError(new Object1Error(value1.getError().getMessage())); return; } Object2 value2 = doSomething2(value1, this.getName()); if (value2.isError()) { sendError(new Object2Error(value2.getError().getMessage())); return; } /* ad infinitum... */ }
Overloaded methods and constructors.
public String toJSON() { return toJSON(true); } public String toJSON(boolean prettyPrint) { /* do work */ return result; } /* test */ @Test public void testToJSON() { ... }; @Test public void testToJSONBoolean() { /* redundant similar test code... */ }
Remote resources. How do I test that my upload API is working (ie: right request method, host, request content type, payload, etc.) without actually doing an upload? These uploads go to servers outside of my control.
public void doUpload() throws IOException { HttpClient client = new HttpClient(); PutMethod putMethod = new PutMethod(...); putMethod.setRequestHeader(...); putMethod.setRequestEntity(new FileInputStreamRequestEntity(...)); /* etc. */ final int responseCode = client.executeMethod(putMethod); }
Testing server interactions with clients.
/* before we even get here, other interactions need to take place */ public void updateClientProfile(UserProfile profile) { // 1. validate the input // 2. update the user in the db // 3. generate an email in HTML // 4. send the email // 5. serve out a view }
Testing at first glance seems easy, until I get to these kind of situations. How do I keep my motivation for testing and write my code to be more testable?
It seems that the more things that a method needs to do, the exponentially more difficult and frustrating unit tests are to write. Do I test simply that the code is calling the right services and methods? Do I write unit tests simply to prove to myself that my code calls the methods I told it to call, or to determine that the logic is right? Help!