nunit / nunit/docs

Questions regarding fluent syntax design for assertions

Open
#331 7 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Dockerfile
Stars
600
Forks
158
Avg merge
16h 8m
Merged PRs (30d)
21

Description

Coming from XUnit + FluentAssertions, I must say I love the TestCase feature of NUnit.

At the same time I feel that the assertion syntax seems all over the place. The fluent attempt mostly applies to reading the assertion, but definitely not to writing them, because Intellisense gives many false suggestions. And for the number of constraints listed in documentation the possibilities still seem rather limited.

There's nothing preventing me from using FluentAssertions, but I'm trying to understand the philosophy in the current assertion/constraint design in NUnit, especially since a lot of work seems to have gone into it.

First example of clunkiness: why does the Has class have a 'Length' and 'Count' which only work on classes with that exact property name? This leads to tests seemingly perfect by reading the code, but still failing at runtime because a collection was of an unexpected type. It's just confusing while there is a syntax that always works...

        [Test]
        public void Test_ItemCount()
        {
            var MyArray = new[] { 1, 2, 3 };
            var MyCollection = new List<int> { 1, 2, 3, };
            var MyEnumerable = Enumerable.Range(1, 3);

            // NUnit assertions

            Assert.That(MyArray, Has.Exactly(3).Items);
            Assert.That(MyArray, Has.Length.EqualTo(3));
            //Assert.That(MyArray, Has.Count.EqualTo(3));        // System.ArgumentException : Property Count was not found on System.Int32[]. (Parameter 'name')

            Assert.That(MyCollection, Has.Exactly(3).Items);
            Assert.That(MyCollection, Has.Count.EqualTo(3));
            //Assert.That(MyCollection, Has.Length.EqualTo(3));  // System.ArgumentException : Property Length was not found on System.Collections.Generic.List`1[System.Int32]. (Parameter 'name')

            Assert.That(MyEnumerable, Has.Exactly(3).Items);
            //Assert.That(MyEnumerable, Has.Count.EqualTo(3));   // System.ArgumentException : Property Count was not found on System.Linq.Enumerable+RangeIterator. (Parameter 'name')
            //Assert.That(MyEnumerable, Has.Length.EqualTo(3));  // System.ArgumentException : Property Length was not found on System.Linq.Enumerable+RangeIterator. (Parameter 'name')


            // FluentAssertions

            MyArray.Should().HaveCount(3);
            MyCollection.Should().HaveCount(3);
            MyEnumerable.Should().HaveCount(3);
        }

Other examples of clunkiness when it comes to Intellisense:

            Assert.That(MyArray, Has.None.Zero);    // Pass
            Assert.That(MyArray, Is.Not.Zero);      // Pass - but probably means something entirely different

            // Why do the following even compile?

            //Assert.That(MyArray, Has.Exactly(3).Items.All.Exist);                      // Expected: IEnumerable But was: Int32 (Parameter 'actual')
            //Assert.That(MyArray, Has.Exactly(3).Items.All.Not.EqualTo(0));             // Expected: IEnumerable But was: Int32 (Parameter 'actual')
            //Assert.That(MyArray, Has.Exactly(3).Items.And.All.All.All.Not.EqualTo(0)); // Expected: IEnumerable But was: Int32 (Parameter 'actual')

Finally, I'm wondering whether it's possible to (1) match using a lambda expression, and (2) drill down into a match to assert its properties. Is there something equivalent in NUnit?

            // FluentAssertions

            MyArray.Should().ContainSingle(x => x > 2).Which.Should().Be(3);
            MyArray.Should().ContainSingle(x => x > 2).Which.Should().Be(3).And.NotBe(4);

            var colors = new[] { Color.Red };
            colors.Should().ContainSingle(x => x.IsKnownColor).Which.R.Should().Be(255);

            // NUnit expected syntax

            //Assert.That(MyArray, Contains.Single(x => x > 2)  (...)    // Syntax error
            //Assert.That(MyArray, Has.One.Match(x => x > 2)    (...)    // Syntax error 
            //Assert.That(colors, Has.Exactly(1).Items.With.R   (...)    // Syntax error

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the assertion and constraint documentation referenced by the examples in the issue, especially Has, Contains, and lambda-based matching. Compare the documented NUnit syntax with the FluentAssertions cases, then clarify the design rationale, supported equivalents, and limitations so each example has an unambiguous documented answer.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
documentation, testing-qa
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.