Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing exception property

I have exception

class SyntaxError : Exception {
    public SyntaxError(int l) {
        line = l;
    }
    public int line;
}

I'm using unit tests to test class Parser which on specific input should throw exception above. I'm using code like this:

    [TestMethod]
    [ExpectedException(typeof(Parser.SyntaxError))]
    public void eolSyntaxError()
    {
        parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
        parser.eol();
    }

Is there any smart simple way to check if SyntaxError.line == 1?

Best I come up with is:

    [TestMethod]
    public void eolSyntaxError()
    {
        try {
            parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");
            parser.eol();
            Assert.Fail();
        } catch (SyntaxError e) {
            Assert.AreEqual(1, e.line);
        }
    }

I don't like it very much, is there better way?

like image 600
graywolf Avatar asked Jan 26 '15 21:01

graywolf


3 Answers

Consider using FluentAssertions. Your test will then look like this:

[TestMethod]
public void eolSyntaxError()
{
    parser.reader = new StringReader("; alfa\n; beta\n\n\n\na");

    Action parseEol = () => parser.eol();

    parseEol
        .ShouldThrow<SyntaxError>()
        .And.line.Should().Be(1);
}

Otherwise, your approach is pretty much as good as it gets.

like image 102
k.m Avatar answered Oct 18 '22 19:10

k.m


You could write a method similar to the one in NUnit

public T Throws<T>(Action code) where T : Exception
{
    Exception coughtException = null;
    try
    {
        code();
    }
    catch (Exception ex)
    {
        coughtException = ex;
    }

    Assert.IsNotNull(coughtException, "Test code didn't throw exception");
    Assert.AreEqual(coughtException.GetType(), typeof(T), "Test code didn't throw same type exception");

    return (T)coughtException;
}

And then you can use it in your test method

Parser.SyntaxError exception = Throws<Parser.SyntaxError>(() => parser.eol());
Assert.AreEqual(1, exception.line);
like image 26
Alexandre Pepin Avatar answered Oct 18 '22 17:10

Alexandre Pepin


As per my comment, if the line at which you encounter the syntax error is relevant, then include it in your custom exception class, like so.

public class SyntaxError : Exception
{
     public SyntaxError(int atLine)
     {
         AtLine = atLine;
     }

     public int AtLine { get; private set; }
}

Then it's easy to test.

EDIT - After having read the question (!) here's a simple additional Assert method which will tidy up your exception assertions.

public static class xAssert
{
    public static TException Throws<TException>(Action a) where TException : Exception
    {
        try
        {
            a();
        }
        catch (Exception ex)
        {
            var throws = ex as TException;
            if (throws != null)
                return throws;
        }
        Assert.Fail();
        return default(TException);
    }
}

Usage as follows...

public class Subject
{
    public void ThrowMyException(int someState)
    {
        throw new MyException(someState);
    }

    public void ThrowSomeOtherException()
    {
        throw new InvalidOperationException();
    }
}

public class MyException : Exception
{
    public int SomeState { get; private set; }

    public MyException(int someState)
    {
        SomeState = someState;
    }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var subject = new Subject();
        var exceptionThrown = xAssert.Throws<MyException>(() => { subject.ThrowMyException(123); });

        Assert.AreEqual(123, exceptionThrown.SomeState);
    }
}
like image 23
Matt Avatar answered Oct 18 '22 17:10

Matt