开发者

Starting a TDD project from scratch

I read a lot of question and answer on TDD and unit testing on SO but I found nothing that answer to that: where do I start from?

Me and team already done a couple of project in which we adopted the use of unit testing, for our code... but code first and then unit testing. At some point of the development process, it became quite natural to write the test first and then the code, bringing us to a more TDD style.

Now we would like to make the next step and try to start a new project with TDD from the beginning. Here's the problem... where to start from? Which is the first test I'd write when I have no code at all?

Let's say, just to have a context to think about, that I have to develop an inte开发者_开发百科rnet application, document-centric, with a little work flow and... something else. But let's start from the beginning: first thing, I want to create a simple page that list all the document (metadata) stored in a table on a DB (quite simple, uh?). Which is the first test I'd write? Let's say that I'm using Hibernate to access the db... would I test the ipothetical method getAllDocuments()? But should I use a mock object to substitute Hibernate? So what am I testing?

I'm a little confuse here... moreover the getAlDocuments() probably will never be a production method... all the collection of documents will be ordered and filtered by something... does it make sense? Any suggestion will be appreciated

Edited:

After reading your answers (and the similar thread at http://programmers.stackexchange.com) I come with a better vision of TDD, but I still have a dubt.

I always though TDD is about making unit test first... never thought about end-to-end test. But let me ask: TDD say you have to write a test and see a compilation error; then you create class and method and you get a test failure; then you implement the method and get the test passed. You cannot write code until there's a test that fail; you cannot write another test until all test pass. Am I right here?

How can I make an end-to-end test as my first test? I should write all the code, in all the layer, to let that test passed. But then I'll have a bunch of classes and methods all tested by my end-to-end test (shouldn't I call it integration test though?). This means I won't need unit test anymore, because I already have a test that cover my code. And I can't write a test that pass already, it's against TDD pratice.

Help me understand this further step ahead please


TDD is not about unit testing - TDD is about driving your development and architecture with tests - with any type of automated tests you need. Do you see the point?

You are starting a new project and you probably have a set of features. You should have some acceptance criteria for features you are going to implement. These criteria can define your top level tests. Let's start either with an end-to-end test (this can be quite hard sometimes because it involves UI which doesn't exist yet) or integration test for these acceptance criteria. Once you have test which is failing you will continue to implement features related to the large test but each this feature will be again driven either with an integration or an unit test. The feature is completed if all top level tests pass.

If you skip large tests (end-to-end, integration) you will develop set of well tested units which will either do not work when integrated together or your architecture will not be very good because of local scope defined by unit tests. Integration and end-to-end tests give you a global scope.

This is described with large example (Java) in the book Growing Object-Oriented Software Guided by Tests.


I typically start from top to bottom. In your case I would start by writing the controller logic of your new page. By controller i mean the code layer just below the UI, mocking everything below. Then write the service layer (if you have one), mocking the data layer. Finally test the data layer also with mocks of the underlying classes (could be ISession in your case). Finally I would write a single integration test of each of the data layer methods and build the page (html).


Since you're attempting to drive development based on the tests, the way to get started is to start with your first feature. For example, let's assume that you have a feature to upload documents. Your first test may be:

public class DocumentManagementTest {
  @Test public void allowsDocumentUploads() {
    DocumentManagement dm = new DocumentManagement();
    Reader mockReader = new MockDocumentReader();

    Document result = dm.createDocument("Document name", mockReader);

    assertEquals("Document name", result.getName());
    assertEquals(0, result.getTags().size());
    assertTrue(mockReader.fileWasRead);
  }
}

I would definitely mock out the database to start with, database setup and teardown is expensive and brittle. Remember though to make very small steps, the test I showed above would have probably evolved over a few iterations. Followup tests that drive out more of the design may be:

@Test public void allowsDocumentRenames() { ... }
@Test public void allowsAddingTagsToExistingDocuments() { ... }
@Test public void showsErrorWhenAddingDocumentThatAlreadyExists() { ... }

Once you've built out a feature such as createDocument you can create a controller around it.

public void doPost(HttpServletRequest req, HttpServletResponse resp) {
  String name = req.getParameter("doc_name");
  Document d = docMgmt.createDocument(name, req.getInputStream());
  // Hand the newly created document to the view engine.
}

I wouldn't worry too much about writing tests for the controller, as it fairly low risk from a complexity standpoint (if the controller gets too much code then it may be a smell that the controller code belongs in another class, possibly your DocumentManagement class).

By building out the functionality one feature at a time and adhering to the SOLID principles you'll slowly grow a system with great test coverage and pretty good OO properties.

Cheers!

Brandon


Start simple, you'll add features incrementally later on. Start from a quick design: which classes, which responsibilities, which relationships. You can use CRC cards. Don't spend too much time on that design as you'll be able to improve it later by Refactoring. Pick up the simplest class to start with to implement a simple capability of the system. For instance, you could first create an empty page.

Start with one class ? what shall its objects do ? How can you verify this is done correctly ? This is the first test.

You could also start without the database, and store your documents in a flat file. You'll refactor to a database later. Then you can start with the getAllDocuments() function.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜