tags:

views:

692

answers:

4

We have a class a class that looks something like the following:

public class Processor
{
    //set timeout in seconds
    private const int TIMEOUT = 600;

    public void Process()
    {
        //DO SOMETHING HERE

        //CHECK TO SEE IF TIMEOUT HAS BEEN HIT
    }
}

Essentially, we'd like to write a unit test to see if a timeout is experienced after the specified amount of time. Obviously, we don't want to have to wait 10 minutes each time we run tests. With this in mind, my question is:

How can we manage this value so that it could be, perhaps, 10 seconds during testing but 10 minutes in production? There are many obvious ways to do this, but I'm trying to determine what the cleanest way would be. Should we expose this as a property? Include it as a constructor parameter? Include it as a method parameter? Use compiler directives?

A: 

Including it as a constructor parameter would be my preference.

The problem with #if debug directives is they are too easy to break if the right symbol is not defined. Plus they are usually used to exclude code from Release (or include code in Debug); It makes testing harder and I've seen them result in subtle errors where code with a side-effect was called in Debug but not in Release (but not recently).

Mitch Wheat
Can you elaborate as to why?
L. Moser
+6  A: 

For your exact scenario, I'd probably have a appSettings variable that determines the timeout for the appropriate server (dev/whatever).

In general though, it is quite appropriate to use the #if DEBUG directive at appropriate times. But in general, you'll only use that when you actually want to prevent compilation of the given code inside it, in release mode.

A classic reason to use such a directive, at least from when I've found, is to stop logging statements being included at all, in release code. Another is when you may include a certain general library in all projects, but certain code in it is not relevant for a given platform you are deploying to (i.e. Compact Framework doesn't have X class, so you use the directive to determine CF mode, and write code accordingly).

Noon Silk
Thank you, this is a great explanation of when you should use directives. And I certainly should have included the appSettings option in my list. In addition, what do you feel the drawbacks are of managing this value in parameters, public setters, or in the directives? Are there any or do you see this as simply a matter of preference?
L. Moser
It's all different. You use a constructor-variable if it makes sense to have a new/maybe differing variable per instance. You use a settable property if it makes sense to change it once an instance is created, and you use an appSettings if it makes sense to have it per release. With the directives, the *only* reason to use it, is for compilation removal. And do be careful about their existance (as Mitch describes). I use them very judiciously. And to be honest, in my personal projects, I virtually never use them. In our commercial stuff, it's as above (CF, Silverlight, Web differences).
Noon Silk
I'm always a little torn when something becomes so crystal clear that I should have seen it to begin with. Thanks for the help, i fully agree.
L. Moser
A: 
#if DEBUG
const int TIMEOUT = 60;
#else
const int TIMEOUT = 600;
#endif

I don't think this would be a big problem. Somewhere along the line you're going to have to use the preprocessor unless you have some other way of defining build target at runtime.

Nick Bedford
+2  A: 

I would mock that code checks for a timeout.

If you something similar to this code:

public class Processor
{
    //set timeout in seconds
    private const int TIMEOUT = 600;

    public void Process(ITimeout timeout)
    {
        //DO SOMETHING HERE

        timeout.CheckTimeout(TIMEOUT);
    }
}

public interface ITimeout
{
    bool CheckTimeout(int timeout);
}

You can mock CheckTimeout method.

You can create a mock class like this one:

public class TimeoutMock : ITimeout
{
    public bool TimeoutExpired;

    public bool CheckTimeout(int timeout)
    {
        return TimeoutExpired;
    }
}

And you test would look something like this:

[TestMethod]
public void TimeoutExpires()
{
    var processor = new Processor();
    var mock = new TimeoutMock();
    mock.TimeoutExpired = true;
    processor.Process(mock);
}
Vadim
+1 for using mocking way, it's the cleanest IMO. Here are some suggestions: 1) TimeoutMock is actually a stub (you are not assertion on TimeOutMock therefore it's a stub) 2) Make ITimeout a field instead of method parameter, it could get value through property or constructor, this way in production code you are not required to work with ITimeout (field gets default value when calling parameter-less constructor) 3) Your test method doesn't Assert - so it will never fail.
Petar Repac
@Petar, You're absolutely right on all three point. I just try to give a fast and simple sample. If I had to write it I would do exactly what you're saying. Only instead of injecting into method, property, or constructor, I would use a DI container.
Vadim