1

In TDD how should you continue when you know what your final outcome should be, but not the processing steps you need to get there?

For example your class is being passed an object whose API is completely new to you, You know the class has the information you need but you don't know how to retrieve it yet: How would you go about testing this?

Do you just focus on the desired result ignoring the steps?

Edit 1

package com.wesley_acheson.codeReview.annotations;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;

public class AnnotationPresenceWarner implements AnnotationProcessor {

    private final AnnotationProcessorEnvironment environment;

    public AnnotationPresenceWarner(AnnotationProcessorEnvironment env) {
        environment = env;
    }

    public void process() {
        //This is what I'm testing
    }

}

I'm trying to test this incomplete class. I want to test I have the right interactions with AnnotationProcessorEnvironment within the process method. However I'm unsure from the API docs what the right interaction is.

This will produce a file that contains details on the occurrence of each annotation within a source tree.

The actual file writing will probably be delegated to another class however. So this class' responsiblity is to create a representation of the annotation occurrences and pass that to whatever classes need to move it.

In non TDD I'd probably invoke a few methods set a breakpoint and see what they return.

Anyway I'm not looking for a solution to this specific example more sometimes you don't know how to get from A to B and you'd like your code to be test driven.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
Wes
  • 6,697
  • 6
  • 34
  • 59
  • Can you give a more concrete example? Have you already decided that you just need a single method - input to output? Is the problem that you haven't read up on the "foreign" API yet, or you're not sure how it will behave in various situations? – Jon Skeet Nov 12 '11 at 08:47
  • @jon edited to give a different example – Wes Nov 12 '11 at 09:07

5 Answers5

4

I'm basing my answer on this video: http://misko.hevery.com/2008/11/11/clean-code-talks-dependency-injection/

If you have a model/business logic class that's supposed to get some data from a service then I'd go about this way:

  1. Have your model class take the data that it needs in the constructor, rather than the service itself. You could then mock the data and unit test your class.

  2. Create a wrapper for the service, you can then unit test then wrapper.

  3. Perform a fuller test where you actually pass the data from the wrapper to the model class.

Tom
  • 964
  • 9
  • 25
3

General Answer TDD can be used to solve a number of issues, the first and foremost is to ensure that code changes do not break existing code in regards to their expected behavior. Thus, if you've written a class with TDD, you write some code first, see that it fails, then write the behavior to make it green without causing other tests to become red.

The side-effect of writing the test cases is that now you have Documentation. This means that TDD actually provides answers to two distinct problems with code. When learning a new API, regardless of what it is, you can use TDD to explore it's behavior (granted, in some frameworks this can be very difficult). So, when you are exploring an API, it's ok to write some tests to provide documentation to it's use. You can consider this a prototyping step as well, just that prototyping assumes you throw it away when complete. With the TDD approach, you keep it, so you can always return back to it long after you've learned the API.

Specific Answer to the Example Given There are a number of approaches which attempt to solve the problem with the AnnotationProcessor. There is an Assertion framework which addresses the issue by loading the java code during the test and asserting the line which the error/warning occurs. And here on Stack overflow

Community
  • 1
  • 1
2

I would create a prototype without the testing to get knowledge of how the api is working. When I got that understanding, I would continue on the TDD cycle on my project

Bassetassen
  • 20,852
  • 8
  • 39
  • 40
2

I agree with Bassetassen. First do a spike to understand what is this external API call does and what you need for your method. Once you are comfortable with the API you know how to proceed with TDD.

skusunam
  • 411
  • 3
  • 12
2

Never ever Unit Test against an unknown API. Follow the same principle is if you didn't own the code. Isolate all the code you are writing from the unknown or unowned.

Write your unit tests as if the environmental processor was going to be code that you were going to TDD later.

Now you can follow @Tom's advice, except drop step 1. Step 2's unit tests now are just a matter of mapping the outputs of the wrapper class to calls on the API of the unknown. Step two is more along the lines of an integration test.

I firmly believe changing your flow from TDD to Prototyping to TDD is a loss in velocity. Stay with the TDD until you are done, then prototype.

Gutzofter
  • 2,003
  • 23
  • 26