5

I've been reading a lot on TDD over the past few months and decided to jump in and try it out with an easy example, I'm just not sure I'm testing for the right things in practice. Here the tests for a custom Data Annotation for validating emails:

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MembershipTest.Tests
{
    [TestClass]
    public class CustomDataAnnotationsTest
    {
        [TestMethod]
        public void CustomDataAnnotations_Email_ReturnTrueIfNull()
        {
            // Arrange
            EmailAttribute attribute = new EmailAttribute();

            // Act
            bool result = attribute.IsValid(null);

            // Assert
            Assert.AreEqual(true, result);
        }

        [TestMethod]
        public void CustomDataAnnotations_Email_ReturnFalseIfInvalid()
        {
            // Arrange
            EmailAttribute attribute = new EmailAttribute();

            // Act
            bool result = attribute.IsValid("()[]\\;:,<>@example.com");

            // Assert
            Assert.AreEqual(false, result);
        }

        [TestMethod]
        public void CustomDataAnnotations_Email_ReturnTrueIfValid()
        {
            // Arrange
            EmailAttribute attribute = new EmailAttribute();

            // Act
            bool result = attribute.IsValid("john.smith@example.com");

            // Assert
            Assert.AreEqual(true, result);
        }
    }
}

And here is the subsequent code written for the test:

using System;
using System.ComponentModel.DataAnnotations;
using System.Net.Mail;

public class EmailAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        //Let RequiredAttribute validate whether the value is required or not.
        if (value == null)
        {
            return true;
        }

        //Check to see if System.Net.Mail can send to the address.
        try
        {
            var i = new MailAddress(value.ToString());
        }
        catch (Exception)
        {
            return false;
        }

        return true;
    }

}

All tests failed initially and then succeeded after writing the code, but are the tests appropriately written? Too much, or too little? I know this is a very simple example, but I want to make sure I'm on the right track before moving on to more complicated things.

Graham Conzett
  • 8,344
  • 11
  • 55
  • 94
  • Perhaps totally offtopic but I'm gonna say it anyway: Dump the VS-integrated testing stuff and get NUnit instead. Like MSBuild vs NAnt, VSTS does not begin to offer the breadth of functionality and flexibility you find in NUnit. Other than that, I think you're approaching this correctly. – kprobst Aug 09 '10 at 17:55
  • 5
    It is indeed totally offtopic :) I think it's a matter of personal preference. I use the Visual Studio testing tools, and they work very well for me, all integrated in VS. – Cocowalla Aug 09 '10 at 18:01
  • 1
    @Coco: They also integrate nicely into TFS. – Steven Sudit Aug 09 '10 at 18:32
  • 2
    I know; I didn't mean to imply otherwise :) I've used TestDriven.NET with NUnit before, and I did like it. But you have to pay for commercial use, and I find the out of the box VS stuff just fine for me. But this really is offtopic and I don't want to cloud the original question further - it's been discussed at length here: http://stackoverflow.com/questions/92869/nunit-vs-visual-studio-2008s-test-projects-for-unit-testing – Cocowalla Aug 09 '10 at 18:39
  • If I were you, I'd ditch the "Arrange", "Act", and "Assert" comments from your code. Just separate each thing by a line break. Also, I'd get even more descriptive with test names. "ReturnTrueIfValid" and "ReturnFalseIfInvalid" are obvious and don't tell what the test actually does. I also disagree with the way you're validating emails, but that's another story for another day. – zowens Aug 09 '10 at 19:32
  • Thank you for the input, everyone. @kprobst I will definitely check out NUnit and look at what it has to offer. @Cocowalla I really like the fact that the VS tools are out of hte box and integrate nicely as well. @zowens I think I'll keep the comments for now, just helps to keep me on task. Are there any comment conventions for naming unit tests that you can share? As an aside for the email thing, it's not a production thing, I'm sure you can figure out from looking at it why it's a good quick/dirty solution for validating. – Graham Conzett Aug 10 '10 at 02:00

1 Answers1

6

I think you are on the right track. At this point I would suggest some refactoring in your tests. Since you are using

EmailAttribute attribute = new EmailAttribute();

in every test. I would suggest creating TestInitialize() and TestCleanup() methods. The TestInitialize would new EmailAttribute and the TestCleanup would null the object out. This is just a matter of preference. Like this

private EmailAttribute _attribute;

[TestInitialize]
public void TestInitialize()
{
  _attribute = new EmailAttribute
}

[TestCleanup]
public void TestCleanup()
{
  _attribute = null;
}
mpenrow
  • 5,563
  • 9
  • 30
  • 36
  • Great point there, going with SetUp/TearDown is definitely a good practice :) – wintermute Aug 09 '10 at 17:44
  • 3
    Your point is very valid, but using the Visual Studio unit testing tools, I think those attributes should be `TestInitialize` and `TestCleanup` respectively (the ones you have used are for NUnit) :D – Cocowalla Aug 09 '10 at 17:47
  • Thanks Cocowalla. I have changed the attribute names. – mpenrow Aug 09 '10 at 17:49