1

I've got an issue in Unit Testing that I've been unable to solve. I think the most succinct way to say it is:

I want to be able to use a Type provided in a Theory InlineAutoMoqData's parameters as the T in Shouldly's Should.Throw method. This would allow me to create different Row Tests (I guess that's Inline Theories in this framework) expecting varying Exception types, should there be multiple associated with a method.

I am unsure if it's possible, but here is an example of the unit test itself.

[Theory]
[InlineAutoMoqData("bork", typeof(FileTypeNotRecognizedException))]
public void Build_ReturnsSpecificException_FileNamePassedIn(string fileName, Type expected, ProcessFactory sut)
{
    Should.Throw<expected>(() => sut.Build(fileName));
}

The questions I looked at, before getting stumped and posting this, were: Dynamically Create a generic type for template and Creating a Generic<T> type instance with a variable containing the Type

Is something like this possible?

Edit:

I see that in xUnit I can achieve this via the Assert.Throws(Type, Delegate) method.

[Theory]
[InlineAutoMoqData("bork", typeof(FileTypeNotRecognizedException))]
public void Build_ReturnsSpecificException_FileNamePassedIn(string fileName, Type expected, ProcessFactory sut)
{
    Assert.Throws(expected, () => sut.Build(fileName));
}

I would still like to know if there is a way to achieve it whenever I want the Type to be in a Generic Method.

Community
  • 1
  • 1
Omnideth
  • 51
  • 7

1 Answers1

1

You can't, except using Reflection, similar to the two links you mentioned.

However, you can do a little trick to achieve what you want. This is ugly and impractical and I don't recommend using it, but just for the fun of it...

Create a generic class containing your parameterized test:

public class Test<T> where T : Exception
{
    public virtual void Build_ReturnsSpecificException_FileNamePassedIn(
        string fileName,
        ProcessFactory sut)
    {
        Assert.Throws<T>(() => sut.Build(fileName));
    }
}

For every parameter (Exception type) you create a class inheriting from the generic one, override the test method and use the InlineAutoMoqData:

public class TestFileNotFound : Test<FileTypeNotRecognizedException>
{
    [Theory]
    [InlineAutoMoqData("bork")]
    public override void Build_ReturnsSpecificException_FileNamePassedIn(string fileName,
        ProcessFactory sut)
    {
        base.Build_ReturnsSpecificException_FileNamePassedIn(fileName, sut);
    }
}
public class TestAnotherException : Test<Exception>
{
    [Theory]
    [InlineAutoMoqData("borg")]
    public override void Build_ReturnsSpecificException_FileNamePassedIn(string fileName,
        ProcessFactory sut)
    {
        base.Build_ReturnsSpecificException_FileNamePassedIn(fileName, sut);
    }
}

Of course, you could do the same using a generic method instead of a generic class, but that seems stupid as well:

public void Build_ReturnsSpecificException_FileNamePassedIn<TException>(string fileName,
    ProcessFactory sut)
    where TException : Exception
{
    Assert.Throws<TException>(() => sut.Build(fileName));
}

[Theory]
[InlineAutoMoqData("bork")]
public void Build_ReturnsSpecificException_FileNamePassedIn(string fileName,
    ProcessFactory sut)
{
    Build_ReturnsSpecificException_FileNamePassedIn<FileTypeNotRecognizedException>(fileName, sut);
}

[Theory]
[InlineAutoMoqData("borg")]
public void Build_ReturnsAnotherException_FileNamePassedIn(string fileName,
    ProcessFactory sut)
{
    Build_ReturnsSpecificException_FileNamePassedIn<Exception>(fileName, sut);
}

As you discovered yourself, xUnit.net has a non-generic Assert.Throws that takes a Type and you should use that instead of this hack.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Marcio Rinaldi
  • 3,305
  • 24
  • 23
  • Why not put the `[Theory]` and `[InlineAutoMoqData]` attributes on the base class test? http://blog.ploeh.dk/2011/05/09/GenericunittestingwithxUnit.net Then you wouldn't need all those overrides. – Mark Seemann Apr 15 '16 at 08:33
  • You're right if the inlined data (fileName) doesn't depend on the exception. That doesn't seem to be the case. It seems that the exception will change as the fileName changes, otherwise, what's the point to inline the exception at all? – Marcio Rinaldi Apr 15 '16 at 12:50