52

I would like to write a callable function that accepts two objects, and compares 30+ properties of those objects with asserts. The issue is this needs to be done for about 20 existing unit tests and most future tests, and writing out the 30+ asserts each time is both time and space consuming.

I currently have a non unit test function that compares the objects, and returns a string with "pass" or a failure message, and use an assert to validate that in each unit test. However, its quite messy and I feel like I'm going against proper unit testing methods.

Is there a way to make a function that is callable from inside unit tests that uses asserts to check conditions?

Pointy
  • 405,095
  • 59
  • 585
  • 614
NewNetProgrammer
  • 523
  • 1
  • 4
  • 4
  • Yes, see [here](https://github.com/nunit/docs/wiki/TestCase-Attribute) and [here](https://github.com/nunit/docs/wiki/TestCaseSource-Attribute). – Felix D. Mar 18 '18 at 20:34

7 Answers7

70

If you are using NUnit 2.5.5 or above, this is possible using the TestCase attribute.

Normal unit tests would be decorated with [Test], but we can replace that as follows:

[TestCase("0", 1)]
[TestCase("1", 1)]
[TestCase("2", 1)]
public void UnitTestName(string input, int expected)
{
    //Arrange

    //Act

    //Assert
}

That type of thing will be the way to do it - obviously take different params.

Look at this for help: http://nunit.org/?p=testCase&r=2.5

ANeves
  • 6,219
  • 3
  • 39
  • 63
stack72
  • 8,198
  • 1
  • 31
  • 35
  • The problem is, my test cases aren't static. I have a manually populated object, and one populated from the database which I want to compare. – NewNetProgrammer Jan 27 '11 at 16:01
  • `expected` should rather be parametrized test's return type, and you should provide test cases with return values instead of parameters. – Robert Koritnik Jan 12 '12 at 21:27
41

To answer the final part, you can of course have Asserts inside another function. Asserts work by raising exceptions which the test runner catches, and interprets as a failure, so have a Test like so will work fine:

public void CheckAsserts(string value)
{
    Assert.IsNotNull(value);
}

[TestCase("yes!")]
public void MyTest(string value)
{
    CheckAsserts(value);
}
Massif
  • 4,327
  • 23
  • 25
  • Thats exactly what I was trying to do, but with two parameters. I had the function as a test case which I think was my issue. Thanks – NewNetProgrammer Jan 27 '11 at 16:10
3

Yes, unit tests are just like any other code.

In particular, check out NUnit.TestCaseAttribute.

jason
  • 236,483
  • 35
  • 423
  • 525
  • I had looked into that, but couldn't see how to setup dynamic parameters. I wanted to compare 20+ manually populated objects with automatically populated objects from the database. Creating a void function with asserts (not a test case) and calling that from my unit tests worked perfectly. Thanks – NewNetProgrammer Jan 27 '11 at 16:04
1

You can use the TestCase attribute:

[TestCase("hostname1parameter")]
[TestCase("hostname2parameter")]
public void Example_TestHostName(string hostname)
{
    ...
}
hwcverwe
  • 5,287
  • 7
  • 35
  • 63
0

You may also benefit from using C# introspection. This allows you to get the names of fields without specifying them in code. You can then invoke them by name.

System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);

This allows you to write certain sorts of tests that will apply to classes that you haven't even written yet.

KellyCoinGuy
  • 61
  • 1
  • 3
0

You'll need the TestCase attribute :

[TestCase("string1",...)
public void test_UnitTest(string Parameter)
{
    ...
    Assert.AreEqual(Parameter, result)
}

Note that this only works with primitive data types like strings and ints - you can't instantiate your own class and use it as a parameter.

Aidan
  • 4,783
  • 5
  • 34
  • 58
0

NUnit [TestCase] attribute provides running a single test with a different set of parameters and you don't have to write separate tests for each parameter. Let us say we have the following class and want to test the IsLatitudeValid() method:

public class CoordinateValidator
{
    public bool IsLatitudeValid(double latitude)
    {
        return latitude is >= -90 and <= 90;
    }
    
    public bool IsLongitudeValid(double longitude)
    {
        return longitude is >= -180 and <= 180;
    }
}

We can use the following test method:

    [TestCase(-90, true)]
    [TestCase(0, true)]
    [TestCase(10, true)]
    [TestCase(90, true)]
    [TestCase(-91, false)]
    [TestCase(91, false)]
    public void TestLatitude(double latitude, bool expected)
    {
        // ARRANGE
        var validator = new CoordinateValidator();

        // ACT
        bool valid = validator.IsLatitudeValid(latitude);

        // ASSERT
        Assert.AreEqual(expected, valid);
    }

This parameterized tests are somehow confusing at first but the trick is to provide a test method (the above) with both input and output/expected parameters. Note that data types of the [TestCase] attributes and the method parameters (that is, double and bool) must match and we test both valid and invalid values.

For more advanced parameterized tests you can look at the [TestCaseSource] and [ValueSource] attributes in the NUnit docs.

If you face with a combinatorial explosion with your parameters, look at the [Values], [Random] and [Range] attribues.

Mustafa Özçetin
  • 1,893
  • 1
  • 14
  • 16