Celeritas
Celeritas

Reputation: 15033

Creating test case for two methods where one is only called if the first one returns true

I have a class which, without going into two much detail, has the methods

  1. public boolean validateData(Person[] p);
  2. public void processData(Person[] p);

Usually these would be used like:

if(validateData(myData)) {
  processData(myData);
}

What's the best way to use JUnit and create test cases for the above two methods? I'm not sure if @Before is correct to use in this situation. I would like to have each @Test call validateData(myData) first, and then if it completes with no error AND returns true then the test should call processData(myData) with the same myData but that would be introducing programing logic into the test case which I don't think is good.

Upvotes: 0

Views: 186

Answers (2)

GhostCat
GhostCat

Reputation: 140407

You mention in your comment that you are worried about redundancy within tests. That is in general a good idea, but you should understand that there are subtle differences between "production" and "test" code.

You see, the main intention of test code is to

a) point out failures quickly

b) make it easy for you to fix them.

In other words: if your class under test has say 3 public methods, then your test class would have at least 3 test methods, too. But most likely, your test class will have on test method for each and any path that you can take through your production methods.

Yes, that leads to a lot of test methods. But the point is: if a single one of them is failing, it might take you only 30 seconds to figure out what is going on - versus: when you only got one test method for the whole thing; you will have to spent quite some time to understand which part of your too-long test is actually failing. But of course: one needs to balance between "my test is easy to understand" and "i am duplicating code all over the place". This podcast gives some good starting points for further thinking about this topic.

And finally, from an SOLID point of view, consider splitting up your production code, too. Classes should be responsible for one thing only - and alone the names of your methods indicate that your class seems to be responsible for doing more than one thing (obviously: validation and processing). Please see that having those two methods also makes your interface unclear - is the user of that class expected to call validate prior to processing; or would "process" include that validation takes places, too?

Upvotes: 0

jropella
jropella

Reputation: 589

Since both methods are public, they should each have their own respective unit tests. Assuming that's the case, you could check something on Person[] to make sure the processData did something.

Something else you could do is refactor your code to use objects rather than just methods - then you can mock out the objects and make sure they are getting called depending on certain conditions:

public interface IDataProcessor {
    void processData(Data data);
}

public class Foo{
    public Foo(IDataProcessor processor) {
        _processor = processor;
    }

    public void bar(Data data){
        if(validateData(data)){
            _processor.processData(data);
        }
    }

    private boolean validateData(Data data){
        return data != null; // or whatever you want
    }

    private IDataProcessor _processor;
}

public class MockProcessor implements IDataProcessor {
    public MockProcessor(){}

    public void processData(Data data){
        CallFlag = true;
    }

    public bool CallFlag = false;
}

Then for your unit test you could do this:

MockProcessor mock = new MockProcessor();
Foo foo = new Foo(mock);
Data data = new Data();
foo.bar(data);
Assert.True(mock.CallFlag);

In C# there's an excellent library called Moq that makes it really easy to create mock implementations of interfaces in unit tests without having to manually define them yourself. There may be something similar available in Java.

Upvotes: 0

Related Questions