Method Chaining base UnitTesting Extension Methods and Dynamic Private Accessor for xUnit.net.
$ dotnet add package ChainingAssertion-xUnit.Bin
Method Chaining base UnitTesting Extension Methods and Dynamic Private Accessor for MSTest, NUnit, xUnit.net. NuGet install supported.
This edition provides .dll file as general NuGet package style.
easy to write, you can use only one method.
// "Is" extend on all object and has three overloads.
// This same as Assert.AreEqual(25, Math.Pow(5, 2))
Math.Pow(5, 2).Is(25);
// lambda predicate assertion.
// This same as Assert.IsTrue("foobar".StartsWith("foo") && "foobar".EndWith("bar"))
"foobar".Is(s => s.StartsWith("foo") && s.EndsWith("bar"));
// collection assert takes variable arguments
// This same as CollectionAssert.AreEqual(Enumerable.Range(1,5), new[]{1, 2, 3, 4, 5})
Enumerable.Range(1, 5).Is(1, 2, 3, 4, 5);if you want to use CollectionAssert Methods then use Linq to Objects and Is.
var array = new[] { 1, 3, 7, 8 };
array.Count().Is(4);
array.Contains(8).IsTrue(); // IsTrue() == Is(true)
array.All(i => i < 5).IsFalse(); // IsFalse() == Is(false)
array.Any().Is(true);
new int[] { }.Any().Is(false); // IsEmpty
array.OrderBy(x => x).Is(array); // IsOrdered// Null Assertions
Object obj = null;
obj.IsNull(); // Assert.IsNull(obj)
new Object().IsNotNull(); // Assert.IsNotNull(obj)
// Not Assertion
"foobar".IsNot("fooooooo"); // Assert.AreNotEqual
new[] { "a", "z", "x" }.IsNot("a", "x", "z"); /// CollectionAssert.AreNotEqual
// ReferenceEqual Assertion
var tuple = Tuple.Create("foo");
tuple.IsSameReferenceAs(tuple); // Assert.AreSame
tuple.IsNotSameReferenceAs(Tuple.Create("foo")); // Assert.AreNotSame
// Type Assertion
"foobar".IsInstanceOf<string>(); // Assert.IsInstanceOfType
(999).IsNotInstanceOf<double>(); // Assert.IsNotInstanceOfTypevar lower = new[] { "a", "b", "c" };
var upper = new[] { "A", "B", "C" };
// Comparer CollectionAssert, use IEqualityComparer<T> or Func<T,T,bool> delegate
lower.Is(upper, StringComparer.InvariantCultureIgnoreCase);
lower.Is(upper, (x, y) => x.ToUpper() == y.ToUpper());
// or you can use Linq to Objects - SequenceEqual
lower.SequenceEqual(upper, StringComparer.InvariantCultureIgnoreCase).Is(true);class MyClass
{
public int IntProp { get; set; }
public string StrField;
}
var mc1 = new MyClass() { IntProp = 10, StrField = "foo" };
var mc2 = new MyClass() { IntProp = 10, StrField = "foo" };
mc1.IsStructuralEqual(mc2); // deep recursive value equality compare
mc1.IntProp = 20;
mc1.IsNotStructuralEqual(mc2);AsDynamic convert to "dynamic" that can call private method/property/field/indexer.
// a class and private field/property/method.
public class PrivateMock
{
private string privateField = "homu";
private string PrivateProperty
{
get { return privateField + privateField; }
set { privateField = value; }
}
private string PrivateMethod(int count)
{
return string.Join("", Enumerable.Repeat(privateField, count));
}
}
// call private property.
var actual = new PrivateMock().AsDynamic().PrivateProperty;
Assert.AreEqual("homuhomu", actual);
// dynamic can't invoke extension methods.
// if you want to invoke "Is" then cast type.
(new PrivateMock().AsDynamic().PrivateMethod(3) as string).Is("homuhomuhomu");
// set value
var mock = new PrivateMock().AsDynamic();
mock.PrivateProperty = "mogumogu";
(mock.privateField as string).Is("mogumogu");// a model
public class Person
{
public int Age { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
}
[TestMethod]
public void TestMethod()
{
// this assertion is fail
var person = new Person { Age = 50, FamilyName = "Yamamoto", GivenName = "Tasuke" };
person.Is(p => p.Age <= 10 && p.FamilyName == "Yamada" && p.GivenName == "Tarou");
}error message shows property values

// Exception Test(alternative of ExpectedExceptionAttribute)
// AssertEx.Throws does not allow derived type
// AssertEx.Catch allows derived type
// AssertEx.ThrowsContractException catch only Code Contract's ContractException
AssertEx.Throws<ArgumentNullException>(() => "foo".StartsWith(null));
AssertEx.Catch<Exception>(() => "foo".StartsWith(null));
AssertEx.ThrowsContractException(() => /* contract method */);
// return value is occured exception
var ex = AssertEx.Throws<InvalidOperationException>(() =>
{
throw new InvalidOperationException("foobar operation");
});
ex.Message.Is(s => s.Contains("foobar")); // additional exception assertion
// must not throw any exceptions
AssertEx.DoesNotThrow(() =>
{
// code
});Parameterized Test like NUnit's TestCase. TestCase takes parameters and send to TestContext's Extension Method "Run".
[TestClass]
public class UnitTest
{
public TestContext TestContext { get; set; }
[TestMethod]
[TestCase(1, 2, 3)]
[TestCase(10, 20, 30)]
[TestCase(100, 200, 300)]
public void TestMethod2()
{
TestContext.Run((int x, int y, int z) =>
{
(x + y).Is(z);
(x + y + z).Is(i => i < 1000);
});
}
}TestCaseSource can take static field/property that types is only object[][].
[TestMethod]
[TestCaseSource("toaruSource")]
public void TestTestCaseSource()
{
TestContext.Run((int x, int y, string z) =>
{
string.Concat(x, y).Is(z);
});
}
public static object[] toaruSource = new[]
{
new object[] {1, 1, "11"},
new object[] {5, 3, "53"},
new object[] {9, 4, "94"}
};There is also "RunAsync" extension method that is async version of "Run" extesion method.
[TestClass]
public class UnitTest
{
public TestContext TestContext { get; set; }
[TestMethod]
[TestCase(1, 2, 3)]
[TestCase(10, 20, 30)]
[TestCase(100, 200, 300)]
public async Task TestTestCaseAsync()
{
await TestContext.RunAsync((int x, int y, int z) =>
{
var actual = await SumAsync(x, y);
actual.Is(z);
});
}
}