1

I'm new in TDD developing and I've just started to do some tests with Nunit 3.7.1, C# and .NET Framework 4.7.

I have this test class:

[TestFixture]
class ProcessTrzlExportTest
{
    private ImportTrzlBatch _import;

    [SetUp]
    public void SetUpImportTrzlBatch()
    {
        _import = new ImportTrzlBatch();
    }

    [Test]
    public void ShouldThrowArgumentExceptionWithNullPath()
    {
        // Arrange
        string path = null;

        // Act
        ActualValueDelegate<object> testDelegate = () => _import.LoadBatchFile(path);

        // Assert
        Assert.That(testDelegate, Throws.TypeOf<ArgumentNullException>());
    }

    [Test]
    public void ShouldThrowArgumentExceptionWithEmptyPath()
    {
        string path = string.Empty;

        // Act
        ActualValueDelegate<object> testDelegate = () => _import.LoadBatchFile(path);

        // Assert
        Assert.That(testDelegate, Throws.TypeOf<ArgumentNullException>());
    }

    [Test]
    public void ShouldThrowArgumentExceptionWithWhiteSpacesPath()
    {
        string path = " ";

        // Act
        ActualValueDelegate<object> testDelegate = () => _import.LoadBatchFile(path);

        // Assert
        Assert.That(testDelegate, Throws.TypeOf<ArgumentNullException>());
    }
}

To test this class:

public class ImportTrzlBatch
{
    public object LoadBatchFile(string path)
    {
        if (string.IsNullOrWhiteSpace(path))
            throw new ArgumentNullException(nameof(path));

        return null;
    }
}

I'm testing that path is not null, empty or white space. I have three test methods to test the same method with three different inputs.

Can I use a private test method to not repeat the code and call it from those three methods with the three different paths?

Another question is that I'm using this:
ActualValueDelegate<object> testDelegate = () => _import.LoadBatchFile(path);

To test if it is throw an ArgumentNullException.

Is there another way to test if throw the exception without using the delegate?

By the way, I have copied the code to check if it throws ArgumentNullException from this SO answer: https://stackoverflow.com/a/33897450/68571

VansFannel
  • 45,055
  • 107
  • 359
  • 626

3 Answers3

4

For these scenario I tend to use TestCase (see below). Like this you write the test only once, and just specifiy the differents values you want to test. In your case null and empty string.

[TestCase(null)]
[TestCase("")]
public void ShouldThrowArgumentException(string path)
{
    // Act
    ActualValueDelegate<object> testDelegate = () => _import.LoadBatchFile(path);

    // Assert
    Assert.That(testDelegate, Throws.TypeOf<ArgumentNullException>());
}

And you can just inline the delegate like this:

[TestCase(null)]
[TestCase("")]
public void ShouldThrowArgumentException(string path)
{
    Assert.That(() => _import.LoadBatchFile(path), Throws.TypeOf<ArgumentNullException>());
}

For more details about the capabilities of TestCase have a look at this documentation here

1

I suggest you to use TestCaseSourceAttribute, you can put all of input cases into one object that implements IEnumerable and then invoke your test for this object. So it looks like this:

    [TestCaseSource(nameof(ShouldThrowArgumentSource))]
    public void ShouldThrowArgumentException(string path)
    {
        // Act
        ActualValueDelegate<object> testDelegate = () => _import.LoadBatchFile(path);

        // Assert
        Assert.That(testDelegate, Throws.TypeOf<ArgumentNullException>());
    }

    private static IEnumerable ShouldThrowArgumentSource()
    {
        yield return string.Empty;
        yield return null;
    }

For more details you can read documentation about TestCaseSource

George Alexandria
  • 2,841
  • 2
  • 16
  • 24
0

Test code is like any other code. If it makes sense to abstract something away, then do it. In your case you don't win much, though. I think Cedric Royer-Bertrand's solution looks nifty. Just add

[TestCase(" ")]

and you are done.

Palle Due
  • 5,929
  • 4
  • 17
  • 32