I recently wanted to unit test a method that required significant setup, and where an invalid method argument would throw an exception while valid values returned easily testable results.

While I could have created a separate test, this really lent itself to using an xUnit Theory. The problem I faced was how to test for the exception but also test for a valid return. I didn't want to write duplicate code within the test itself, such as declaring the service twice.

Some research and experimentation led to the approach below. The trick is to declare a delegate function, then use FluentAssertions to either catch the invocation exception, or to invoke the function and return the value.

Here's a simple Class Library app to demonstrate the technique. I kind of love this because there's no wasted or duplicate code.

using System;
using FluentAssertions;
using Xunit;

namespace FluentAssertionsInvoking
{
    public class CustomerService_Should
    {
        [Theory]
        [InlineData(null)]
        [InlineData("Marcus Welby")]
        public void Return_a_customer_or_throw_an_exception(string name)
        {
            // arrange
            var expected = new Customer() { Name = name };
            var customerService = new CustomerService(expected);

            // act
            Func<CustomerService, Customer> action = service => service.GetCustomer();

            // assert
            // Exception condition
            if (name == null)
            {
                customerService.Invoking(action).Should().Throw<Exception>();
            }
            else
            // Valid condition
            {
                var result = action.Invoke(customerService);
                result.Should().BeEquivalentTo(expected);
            }
        }
    }

    public class Customer
    {
        public string Name { get; set; }
    }

    public class CustomerService
    {
        private Customer _customer;
        public CustomerService(Customer customer)
        {
            _customer = customer;
        }
        public Customer GetCustomer()
        {
            if (_customer.Name == null) { throw new Exception(); }
            return _customer;
        }
    }
}

References

Bonus

Here's the xunit.runner.json to show only method names in the Test Runner output. Remember to set the file to Copy to Output.

{
  "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
  "methodDisplay": "method"
}