Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending XUnit Assert class with new asserts

I'm trying to extend the xUnit assert method by adding some selenium functionality

namespace MyProject.Web.Specs.PageLibrary.Extensions
{
    public static class AssertExtensions
    {
        public static void ElementPresent(this Assert assert, ...)
        {
            if (...)
            {
                throw new AssertException(...);
            }
        }
    }
}

But I get this compile error when I try to use it.

using MyProject.Web.Specs.PageLibrary.Extensions;    
using Xunit;
...

public void DoSomething()
{
    Assert.ElementPresent(...);
}

And the error

Error   5   'Xunit.Assert' does not contain a definition for 'ElementPresent'

Does anyone know if this is possible or where I'm going wrong?

like image 209
Neil Avatar asked Apr 24 '13 14:04

Neil


People also ask

How do you Assert two objects are equal in xUnit?

You'll have to implement IEquatable<T> for your objects, and then Assert. Equals will work. Assert. Same() compares by reference; it asserts that Obj1 and Obj2 are the same object rather than just looking the same.

What is IClassFixture in xUnit?

Important note: xUnit.net uses the presence of the interface IClassFixture<> to know that you want a class fixture to be created and cleaned up. It will do this whether you take the instance of the class as a constructor argument or not.

What xUnit attributes mark a method as a unit test?

The only unit test currently implemented is the ValidPassword() method. This method is decorated with the Fact attribute, which tells xUnit that this is a test.


2 Answers

Edit 2 xUnit 2 eventually ended up moving the assertions into a separate assembly altogether. There are both compiled and source only packages of this on NuGet, and the Assert class is partial, so by using the source only version of the package, Assert becomes very easily extensible (in C#, that is).

Edit For more completeness: xUnit 2 removes this extension point and recommends using extension methods along the lines of 'fluent' assertion libraries.


For completeness, here's a description of the "official" way of extending Assert (which surprisingly has not been mentioned at all, despite the fact that Brad Wilson even joined the discussion).

From version 1.5 (according to Brad's blog), xUnit.Extensions has explicit support for this via the Assertions and TestClass classes. It works like this:

TestClass has a property called Assert that is of type Assertions which relays all the methods on Xunit.Assert. Because TestClass.Assert is an instance, you can add methods to it through extension methods on Assertions:

public static class AssertionsExtensions
{
    public static void DeepEquals(this Assertions assertions, XNode expected, XNode actual)
    {
        assertions.True(XNode.DeepEquals(expected, actual)); // You can also use Assert.True here, there's effectively no difference.
    }
}

Now you need to have your test class derive from Xunit.Extensions.TestClass (confusingly, there is also Xunit.TestClass, which is not what you want), and the Assert property will "shadow" the Xunit.Assert type if you don't qualify the name explicitly.

In your test class that derives from TestClass, you can now use

Assert.DeepEquals(expectedXml, actualXml);

The only real difference from a built-in xUnit assertion (apart from the fact that syntax coloring for Assert is that of an identifier, not a type) is that when it fails, you simply get a TrueException, not a specific DeepEqualsException that could hypothetically tell you where the comparison failed. But of course you could build that too in the very same way.

like image 161
TeaDrivenDev Avatar answered Oct 24 '22 02:10

TeaDrivenDev


Summary of the solution for xUnit 2. (Worked for me for version 2.1.0 from NuGet.)

Assert is a partial class that you can extend by adding another part. To be able to do that you need to compile the Assert assembly from sources. You can use xunit.assert.source NuGet to get the sources.

The Steps

  1. Remove reference to the xunit.assert NuGet package from the project.
  2. Instead install xunit.assert.source package.
  3. In the Xunit namespace, define public partial class Assert and add your custom asserts there.
  4. In your test project install the xunit.extensibility.execution package (or otherwise there will be a conflict between two different Assert classes and tests won't run becasue the xunit.execution.*.dll will be missing)

Example of a custom assert:

namespace Xunit
{ 
    public partial class Assert
    {
        public static void ArraySegmentEqual<T>(
            T[] expectedSequence, T[] buffer, int offset = 0)
        {
            for (int i = 0; i < expectedSequence.Length; i++)
            {
                int b = i + offset;

                True(buffer[b].Equals(expectedSequence[i]),
                    $"Byte #{b} differs: {buffer[b]} != {expectedSequence[i]}");
            }
        }
    }
}

Note: Other answers and edits also point to the solution, but it took me quite some tome to figure it out from there. Also, I do not claim this is the only or the best option.

like image 13
Premil Avatar answered Oct 24 '22 01:10

Premil