Friday, March 05, 2010

The case of the missing assert

I was looking at a friend of mines code late last night and he was writing his tests in MSTest. The test he wrote was an expected exception test.

        [TestMethod]
        [ExpectedException(typeof(SomeException))]
        public void CanDoSomething_WithSomeThingThatThrows_ReturnsTrue()
        {
            var something = SomeFactory.GetSomething();
            something.DoSomething(x => { throw new NotImplementedException(); });

            var result = something.DoSomethingElse<ISomeThingElse>();

            Assert.IsTrue(true);
        }
I was tired, it was late, I'm used to a using different test framework but I got in contact straight away.
....spotted something in your codez. You're Assert is true everytime.
Of course dear reader you will have spotted the ExpectedException attribute as you, unlike me are not an idiot but my eyes see:
        [TEST BLAH]
        [yes i didn't spot the attrib here]
        public void STUFF_I_WILL_READ_IF_TEST_IS_NOT_OBVIOUS()
        {
            //SOME ARRANGING STUFF
            ..blah
            //THIS IS IMPORTANT
            var result = something.DoSomethingElse<ISomeThingElse>();
            //AND SO IS THIS
            Assert.IsTrue(true);
        }
In my semi-comatosed state my eyes fix on Assert.IsTrue(true) and I can look away from it. I'm used to NUnit's (and xUnit and mbUnit) Assert.Throws
        [TEST BLAH]
        public void STUFF_I_WILL_READ_IF_TEST_IS_NOT_OBVIOUS()
        {
            //SOME ARRANGING STUFF
            ..blah
            //THIS IS IMPORTANT
            Assert.Throws(()=> something.DoSomethingElse<ISomeThingElse>());

        }
However some frameworks don't support this. So you've got 2 options.
Option 1 Attribute and fail.
        [TestMethod]
        [ExpectedException(typeof(SomeException))]
        public void CanDoSomething_WithSomeThingThatThrows_ReturnsTrue()
        {
            var something = SomeFactory.GetSomething();
            something.DoSomething(x => { throw new NotImplementedException(); });

            var result = something.DoSomethingElse<ISomeThingElse>();

            Assert.Fail();
        }
As my eyes always look the assert and so if I see a fail. I'll look to see why.
Option 2 No Attribute try catch
        [TestMethod]
        public void CanDoSomething_WithSomeThingThatThrows_ReturnsTrue()
        {
            var something = SomeFactory.GetSomething();
            something.DoSomething(x => { throw new NotImplementedException(); });
            try
            {
                var result = something.DoSomethingElse<ISomeThingElse>();
                Assert.Fail();
            }
            catch (SomeException)
            {
                Assert.IsTrue(true);
            } 
            catch (Exception)
            {
               Assert.Fail();
            }
        }
And what happens when we want to invoke an action that doesn't expect anything. That you just want to run to see if doesn't fail. Well you've got Assert.DoesNotThrow in most .Net unit testing frameworks.
You can call the Assert.IsTrue(True);
        [TestMethod]
        public void CanDoSomething_WithSomeThingThatDoesnotThrow()
        {
            var something = SomeFactory.GetSomething();
            something.DoSomething(x => { throw new NotImplementedException(); });
           Assert.IsTrue(True);
        }
Or just drop the assert.
        [TestMethod]
        public void CanDoSomething_WithSomeThingThatDoesnotThrow()
        {
            var something = SomeFactory.GetSomething();
            something.DoSomething(x => { throw new NotImplementedException(); });
          
        }
So with MStest you can't use Assert.Throws but you do have options. Mine is to use another framework ;)