NExpect: not just pretty syntax!
Tags: tdd, nexpect, csharp
Published: 2020-08-21 14:19:32

I've written about [NExpect](https://github.com/fluffynuts/nexpect) a few times before:
- [Introduction](https://dev.to/fluffynuts/introducing-nexpect-555c)
- [Level 1](https://dev.to/fluffynuts/nexpect-level-1-simple-stuff-58bd)
- [Level 2](https://dev.to/fluffynuts/nexpect-level-2-collections-2afi)
- [Level 3](https://dev.to/fluffynuts/nexpect-level-3-you-re-the-secret-sauce-4lpp)

If you'd like to learn more first, open those up in other tabs and have a look. I'll wait...

![Animated image of a guest on the Tonight Show saying "I'll be here when you're ready", and sliding out of sight](https://media.giphy.com/media/xT0BKAIqku8n6g3r6U/giphy.gif "I'll be here when you're ready...")

I've had a preference for using NExpect myself, but I'm obviously biased: I had a developer-experience with NUnit assertions which I found lacking, so I made a whole new extensible assertions library.

But there's always been something that I haven't been able to qualify about _why_ I prefer NExpect over NUnit assertions. I've even gone so far as to tell people to just use either, because they're both good, and I don't want to be _that guy_ who tells people to use his stuff.

Though the deep-equality testing is _really_ convenient and NUnit doesn't do that...

Today, that changes. I have a good reason to promote NExpect over NUnit now, apart from all of the obvious benefits of NExpect:
- fluid expression
- extensibility
- deep-equality testing
- better collection matching

_Today I found that NExpect can tell you earlier when you've broken something than NUnit can._

## Explain how?

Consider this innocuous code:
```csharp
using NUnit.Framework;

[TestFixture]
public class Tests
{
  [Test]
  public void ShouldPassTheTest()
  {
    var result = FetchTheResult();
    Assert.That(result, Is.EqualTo(1));
    // or, the olde way:
    Assert.AreEqual(result, 1);
  }

  private int FetchTheResult()
  {
    return 1;
  }
}
```

Of course, that passes.

The interesting bit here is the usage of `var`, which, in C#, means "figure out the type of the result at compile-time and just fill it in". Long ago, that line would have had to have been:

```csharp
int result = FetchTheResult();
```

`var` has some distinct advantages over the prior system. It's:
- shorter to write
- you only have to remember one "muscle-memory" to store a result (always `var ___ = ___`)
- it means that if you _do_ change return types, things are updated for you. 

In theory (and practice), it makes you quicker on the first run and when you refactor.

The problem comes in when those strong types are discarded by code which compiles perfectly. The compiler can't save you from yourself _every time_!

## Enter the refactor

When we update the above so that `FetchTheResult` now returns a complex object, the code _will still compile_:

```csharp
using NUnit.Framework;
[TestFixture]
public class Tests
{
  [Test]
  public void ShouldPassTheTest()
  {
    var result = FetchTheResult();
    Assert.That(result, Is.EqualTo(1));
    // or, the olde way:
    Assert.AreEqual(result, 1);
  }

  public class Result
  {
    public int Value { get; set; }
    public DateTime Created { get; set; }
  }
  private int FetchTheResult()
  {
    return new Result()
    {
      Value = 1,
      Created = DateTime.Now
    };
  }
}
```

for the intent of the flow of logic, we're still returning the value `1`, but we've also attached a `DateTime` property to that to indicate when that result was created. Rebuilding, we find that everything builds just fine, and perhaps we forget to re-run tests (or perhaps this function is very far away from where the result is being used, so we don't realise that we just broke a test somewhere else).

This is because the NUnit assertions fall back on `object` for types:
- `Assert.That` is genericised for the first parameter, so it has a fixed type there, but takes a Constraint for the second parameter -- and a Constraint can house anything, because it casts down to `object`
- `Assert.AreEqual` has an overload that expects two `objects`, so it will fall back on that, and also compile.

The test will fail -- if you remember to run it (or _when_ CI runs it).


## So how does NExpect help?

If we'd written the first code like so:
```csharp
using NUnit.Framework;
using NExpect;
using static NExpect.Expectations;

[TestFixture]
public class Tests
{
  [Test]
  public void ShouldPassTheTest()
  {
    var result = FetchTheResult();
    Expect(result).To.Equal(1);
  }

  private int FetchTheResult()
  {
    return 1;
  }
}
```

then the refactor would have caused a compilation failure at second line of the test, since NExpect carries the type of `result` through to the `.Equal` method. 

> actually, it does a bit of _up-casting_ trickery so that you   
> can, for example, `Expect((byte)1).To.Equal(1);`, but that's 
> beside the point for this particular post...

So the _second_ the refactor had gone through, the test wouldn't compile, which means I could find the failure even before running the tests and update them accordingly, instead of waiting for tests to fail at a later date.

## Conclusion
Strongly-typed languages have a certain amount of popularity because the types can help us to avoid common errors. This is why TypeScript is so popular. C# _is_ strongly typed, but there are ways that the strength of that typing can be diluted, and one of those ways is found in NUnit assertions. 

NExpect protects you here and alerts you about potentially breaking changes to your code before even running tests. Neat, huh?

I think I'll pat myself on the back for that 🤣

![Little girl pats herself on the back](https://media.giphy.com/media/9PrvrbV4DiUUCiGPgQ/giphy.gif "I think I deserve a pat on the back")