views:

46

answers:

2

IF I am testing something related to an error, I might want to see the message or stack trace in the console initially. After I'm satisfied with the test I typically do not want to have the console cluttered with anything that might help quickly spot and diagnose a failing test. When refactoring though, it is sometimes useful to once again output additional info. So I have lots of lines scattered about that I comment / uncomment, like:

// System.Diagnostics.Debug.WriteLine(msg);

What is a cleaner way to do this?

Cheers,
Berryl

=== EDIT

Here is an example of what I mean, updated to use a Log service as per Josh's suggestion here.

As a unit test, I want to assert that an error will be displayed to the user, in this case because there is a duplicate name for a new department. I can and do automate that the message is being generated with the correct content.

The message also has to pass a basic smell test that can't be automated though - is it a well structured sentence that most users will quickly understand and know how to fix? I don't want to have to fire up the ui and get a user to make sure it isn't outright silly, so I want to eyeball it by printing it out. And as I alluded to earlier, this is just noise except for the few times the message changes.

    [Test]
    public void WhenThePropertyIsChanged_IfDuplicateIsFound_DuplicateNameIsPartOfBrokenRuleMessage()
    {
        const string newName = "Blah";
        // force a duplicate
        _dao.Stub(x => x.FindByName(newName)).Return(new Department(newName)); 

        var vm = _masterVm.Departments.Last();

        vm.Name = newName;
        var msg = vm.GetBrokenRules().First().Description;
        Log.Service.WriteLine(msg); <=== print it
        Assert.That(msg, Is.StringContaining(newName));
        Assert.That(vm.BrokenRules.First().Description, Is.EqualTo(msg));
    }
+2  A: 

Wrap your logging statements into a service and code to an interface.

public interface ILoggingService
{
    void WriteLine(String msg);
}

Create a static class that allows access to the logging service, but allows you to set the service.

internal static class Log
{
    private static ILoggingService _loggingService;
    internal static ILoggingService Service
    {
        get{ return _loggingService ?? (_loggingService = new DefaultLoggingService()); }
        set{ _loggingService = value; }
    }
}

Now you can implement a service in just your tests that writes to the Debug stream.

public class DebugLoggingService: ILoggingService
{
    public void WriteLine(String msg)
    {
        System.Diagnostics.Debug.WriteLine(msg);
    }
}

Log.Service = new DebugLoggingService();

Your code can stay the same now, and you only have to change your DebugLoggingService by commenting out the lines there. Or better yet, you could wrap it in a #if DEBUG ... #endif statement.

Josh
@Josh. Pretty slick. If you were using Log4Net anyway would you still implement the service or does Log4Net do that??
Berryl
@Berryl -- I typically stick even my third party stuff behind an interface boundary so I don't get "framework" locked. I use Entlib a lot for logging, but I still use service boundaries like above. In that way, if I ever want to swap out my logging framework for something else I can.
Josh
+1  A: 

It's by better to use assertions that console output. If the computer can display it, it also can verify it, a lot faster than you can.

If you do not have true unit tests, and are testing manually, you could use Log4, so you can easily tune the trace level you want.

philippe
@philippe. It wouldn't be a unit test without an assertion; what I'm talking about is fine tuning type stuff that is sometimes useful in *addition* to the assertion.
Berryl
@Berryl: agreed, but not everyone is using the unit testing term for the same thing. I seemed to me that you might not be writing automatic unit tests, hence my comment. <br>That being said, you should generally not need print statement. Do you have them in your code or in your tests ? Those in tests shall definitively be converted into assertions. <br>Nevertheless, the Log4j or whatever advice remains.
philippe
@phillipe. See edit at end of original post to understand the motivation for the print and a sample test case with it. The total percentage of unit tests that will merit any print out is very small. If I knew log4net well I probably would use it in someway but Josh's suggestion is a definite upgrade over what I was doing before. Cheers
Berryl