Search code examples
c#unit-testingextension-methodsxunit

Create a test for a void extension method


How exactly do you create a test for a void extension method? I'm using XUnit.

I have a extension method that throws an exception if something is true.

public static void IsClosed(this List<Contract> contracts)
{
    if (contracts.Any(x => x.Status == Status.Closed) throw new IsClosedException();
}

In the test I cannot ceate for example :

var sut = contracts.IsClosed();

Do I need to mock a list of contracts?

var contracts = Mock<List<Contract>>());

But what then?

contracts.Setup...?

Or

contracts.Invoke...?

Solution

  • [Fact]
    void ShouldThrowIsClosedException()
    {
        // Just create a list that you expect to trigger the Exception ...
        List<Contract> contracts = new() { new() {Status == Status.Closed}};
       
        Assert.Throws<IsClosedException>(contracts.IsClosed);
    }
    

    should do the trick.

    As remarked by Jon Skeet: A complementary test should be added, too. (I.e. where the exception is not thrown.)

    If you want to get really fancy, you can also test different lists:

    [Theory]
    [ClassData(typeof(ShouldThrowIsClosedExceptionTestData))]
    void ShouldThrowIsClosedException(List<Contract> contracts)
    {
        Assert.Throws<IsClosedException>(contracts.IsClosed);
    }
    
    // ...
    public class ShouldThrowIsClosedExceptionTestData 
        : TheroyData<List<Contract>>
    {
        public ShouldThrowIsClosedExceptionTestData()
        {
    // Single entry
            Add (new List<Contract>() { new() {Status == Status.Closed}});
    // Multiple entries
            Add (new List<Contract>() { new() {Status == Status.Closed}, new() {Status == Status.Closed}});
    // Mixed entries
            Add (new List<Contract>() { new() {Status == Status.Closed}, new() {Status == Status.Open}});
            Add (new List<Contract>() { new() {Status == Status.Open}, new() {Status == Status.Closed}});
        }
    }