Unit testing massively benefits from following the Arrange / Act / Assert pattern. I’ve seen tests that are not written in this way, and they can be sprawling and indecipherable, either testing many different things in series, or testing nothing at all except the .Net Framework.
I recently found an issue while trying to test for an exception being thrown, which is that Nunit (and probably other frameworks) test for an exception by accepting a delegate to test. Here’s an example:
[Test] public void Test_ThrowException_ExceptionThrown() { // Arrange TestClass tc = new TestClass(); // Act / Assert Assert.Throws(typeof(Exception), tc.ThrowException); }
We’re just testing a dummy class:
public class TestClass { public void ThrowException() { throw new Exception("MyException"); } }
C# 7 – Inline functions
If you look in the references at the bottom, you’ll see something more akin to this approach:
public void Test_ThrowException_ExceptionThrown2() { // Arrange TestClass tc = new TestClass(); // Act TestDelegate throwException = () => tc.ThrowException(); // Assert Assert.Throws(typeof(Exception), throwException); }
However, since C# 7, the option on a local function has arrived. The following has the same effect:
[Test] public void Test_ThrowException_ExceptionThrown3() { // Arrange TestClass tc = new TestClass(); // Act void CallThrowException() { tc.ThrowException(); } // Assert Assert.Throws(typeof(Exception), CallThrowException); }
I think that I, personally, still prefer the anonymous function for this; however, the local function does present some options; for example:
[Test] public void Test_ThrowException_ExceptionThrown4() { void CallThrowException() { // Arrange TestClass tc = new TestClass(); // Act tc.ThrowException(); } // Assert Assert.Throws(typeof(Exception), CallThrowException); }
Now I’m not so sure that I still prefer the anonymous function.
References
http://stackoverflow.com/questions/33897323/nunit-3-0-and-assert-throws
https://pmbanugo.wordpress.com/2014/06/16/exception-testing-pattern/