HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

TDD workflow best-practices for .NET using NUnit

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
workflownunitnetpracticesforusingtddbest

Problem

I'm starting to dive into TDD with NUnit and despite I've enjoyed checking some resources I've found here at stackoverflow, I often find myself not gaining good traction.

So what I'm really trying to achieve is to acquire some sort of checklist/workflow —and here's where I need you guys to help me out— or "Test Plan" that will give me decent Code Coverage.

So let's assume an ideal scenario where we could start a project from scratch with let's say a Mailer helper class that would have the following code:

(I've created the class just for the sake of aiding the question with a code sample so any criticism or advice is encouraged and will be very welcome)

Mailer.cs

```
using System.Net.Mail;
using System;

namespace Dotnet.Samples.NUnit
{
public class Mailer
{
readonly string from;
public string From { get { return from; } }

readonly string to;
public string To { get { return to; } }

readonly string subject;
public string Subject { get { return subject; } }

readonly string cc;
public string Cc { get { return cc; } }

readonly string bcc;
public string BCc { get { return bcc; } }

readonly string body;
public string Body { get { return body; } }

readonly string smtpHost;
public string SmtpHost { get { return smtpHost; } }

readonly string attach;
public string Attach { get { return Attach; } }

public Mailer(string from = null, string to = null, string body = null, string subject = null, string cc = null, string bcc = null, string smtpHost = "localhost", string attach = null)
{
this.from = from;
this.to = to;
this.subject = subject;
this.body = body;
this.cc = cc;
this.bcc = bcc;
this.smtpHost = smtpHost;
this.attach = attach;
}

public void SendMail()
{
if (string.IsNullOrEmpty(Fro

Solution

It is important to get one's mindset in a TDD mode beforehand. What I mean by this is

1) Identify the responsibility of a class - this helps in identifying the test cases.
2) Identify the interactions of the class with external dependencies - Unit testing shouldn't be testing the behaviour of the external dependency.

In this case - you have written a wrapper class around SendMail whose responsibility is to "Collect and Despatch".

I'd say SmtpClient is a dependency - you should be able to Mock it's behaviour in your test.

Mailer.cs

using System.Net.Mail;
using System;

namespace Dotnet.Samples.NUnit
{
    public class Mailer
    {
        readonly string from;
        public string From { get { return from; } }

        readonly string to;
        public string To { get { return to; } }

        readonly string subject;
        public string Subject { get { return subject; } }

        readonly string cc;
        public string Cc { get { return cc; } }

        readonly string bcc;
        public string BCc { get { return bcc; } }

        readonly string body;
        public string Body { get { return body; } }

        readonly string smtpHost;
        public string SmtpHost { get { return smtpHost; } }

        readonly string attachment;
        public string Attachment { get { return Attachment; } }

        private SmtpClient smtpClient;

        public Mailer(string from = null, string to = null, string body = null, string subject = null, string cc = null, string bcc = null, string smtpHost = "localhost", string attachment = null, SmtpClient smtpClient= new SmtpClient())
        {
            this.from = from;
            this.to = to;
            this.subject = subject;
            this.body = body;
            this.cc = cc;
            this.bcc = bcc;
            this.smtpHost = smtpHost;
            this.attachment = attachment;
        }

        public void SendMail()
        {
            if (string.IsNullOrEmpty(From))
                throw new ArgumentNullException("Sender e-mail address cannot be null or empty.", from);

            MailMessage mail = new MailMessage();
            smtpClient.Send(mail);
        }
    }
}


Testing SendMail

[Test]
public voud ShouldCallSendOfSmtpClientWhenSendMailIsCalled
{
    //Stub & Setup
    var mockSmtpClient = MockRepository.GenerateMock();
    var mailer = new Mailer(smtpClient: mockSmtpClient);

    //Act
    var message = new MailMessage();
    mailer.SendMail(message);

    //Assert
    mockSmtpClient.AssertWasCalled(m=>m.Send(Arg.Is.Anything));
}

Code Snippets

using System.Net.Mail;
using System;

namespace Dotnet.Samples.NUnit
{
    public class Mailer
    {
        readonly string from;
        public string From { get { return from; } }

        readonly string to;
        public string To { get { return to; } }

        readonly string subject;
        public string Subject { get { return subject; } }

        readonly string cc;
        public string Cc { get { return cc; } }

        readonly string bcc;
        public string BCc { get { return bcc; } }

        readonly string body;
        public string Body { get { return body; } }

        readonly string smtpHost;
        public string SmtpHost { get { return smtpHost; } }

        readonly string attachment;
        public string Attachment { get { return Attachment; } }

        private SmtpClient smtpClient;

        public Mailer(string from = null, string to = null, string body = null, string subject = null, string cc = null, string bcc = null, string smtpHost = "localhost", string attachment = null, SmtpClient smtpClient= new SmtpClient())
        {
            this.from = from;
            this.to = to;
            this.subject = subject;
            this.body = body;
            this.cc = cc;
            this.bcc = bcc;
            this.smtpHost = smtpHost;
            this.attachment = attachment;
        }

        public void SendMail()
        {
            if (string.IsNullOrEmpty(From))
                throw new ArgumentNullException("Sender e-mail address cannot be null or empty.", from);

            MailMessage mail = new MailMessage();
            smtpClient.Send(mail);
        }
    }
}
[Test]
public voud ShouldCallSendOfSmtpClientWhenSendMailIsCalled
{
    //Stub & Setup
    var mockSmtpClient = MockRepository.GenerateMock<SmtpClient>();
    var mailer = new Mailer(smtpClient: mockSmtpClient);

    //Act
    var message = new MailMessage();
    mailer.SendMail(message);

    //Assert
    mockSmtpClient.AssertWasCalled(m=>m.Send(Arg<MailMessage>.Is.Anything));
}

Context

StackExchange Code Review Q#2699, answer score: 4

Revisions (0)

No revisions yet.