c# - How to write my first Unit-test for Email-function -


this smaller part of email sending application, i'm trying implement unit-testing application. , i've read bit on unit testing far, , understand should test single functions instead of entire classes. how test code?

private void send(ienumerable<customer> customers, string body)         {             string titleofemail = "welcome new customer @ company!";             string ouremailaddress = "info@company.com";             int numberofretriesonerror = 2;             int delayonerror = 10;              foreach (var customer in customers)             {                 (int = 0; <= numberofretriesonerror; ++i)                 {                     try                     {                         sender.send(ouremailaddress, customer.email, titleofemail);                         return;                     }                     catch (smtpexception e)                     {                         if (i < numberofretriesonerror)                             thread.sleep((i + 1) * delayonerror);                         else                             errors.add(e.message + customer); // include customeremail                     }                 } } 

edit: rest of information not needed rest

public interface imailsender {     void send(string from, string to, string body); } sealed class nullmailsender : imailsender {     void imailsender.send(string from, string to, string body)     {      } }  sealed class smtpmailsender : imailsender {     void imailsender.send(string from, string to, string body)     {         system.net.mail.mailmessage mail = new system.net.mail.mailmessage();         mail.from = new system.net.mail.mailaddress(from);         system.net.mail.smtpclient smtp = new system.net.mail.smtpclient("yoursmtphost");         mail.to.add(to);         mail.body = body;         smtp.send(mail);      } }      

and part rest of top function, whole class

public class sendingmail {     public list<string> errors { get; } = new list<string>();      public ienumerable<customer> customers { get; set; }      public ienumerable<order> orders { get; set; }      public imailsender sender { get; set; }      public void sendwelcomeemails()     {         var template = resources.welcomeemailtemplate;         send(getnewcustomers(), resources.welcomeemailtemplate);     }      public void sendcomebackemail()     {         var template = resources.welcomeemailtemplate;         var emailcontent = string.format(template);         send(getcustomerswithoutrecentorders(), resources.comebackemailtemplate);     }      private ienumerable<customer> getnewcustomers()     {         var yesterday = datetime.now.date.adddays(-1);         return customers.where(x => x.createddatetime >= yesterday);     }     private ienumerable<customer> getcustomerswithoutrecentorders()     {         var onemonthago = datetime.now.date.addmonths(-1);          return customers.where(c => {             var latestorder = orders                 .where(o => o.customeremail == c.email)                 .orderbydescending(o => o.orderdatetime)                 .firstordefault();              return latestorder != null                 && latestorder.orderdatetime < onemonthago;         });     } 

okay, think might tripping haven't broken out function according srp (single responsibility principle.)

put way: function responsible for?

  1. setting title & from-address of email
  2. looping through each customer
  3. calling sender
  4. handling errors

... right off bat, unit tests have try handle separate things in calls function. unit tests hate that.

but if wrote function differently?

// needs system.net.mail mailmessage class - write own private void send(ienumerable<customer> customers, string body) {     foreach(customer customer in customers)         send(customer, body); } private void send(customer customer, string body) {     mailmessage message = generatemessage(customer, body);     // code sending/retrying; omitted keep code short } private mailmessage generatemessage(customer customer, string body) {     string subject = "...";     string = "...";     string = customer.email;     mailmessage retval = new mailmessage(from, to, subject, body);     return retval; } 

okay, take @ unit testing picture now. suddenly, can test generation of email message without sending email. create dummy customer, pass generatemessage function, , validate results passes (no email gets sent.)

as emailing itself? that's bit tougher. you've got 2 options. option #1 generate dummy customer personal/group's email address, , have go ahead , send email you. not ideal, it'll make sure email code works. option modify sender class (or wrap it, if don't control it) - like:

interface isender {     void send(/* args you've got send function */); } class sender : isender {     void send(/* args */) { /* code */ } } class dummysender : isender {     void send(/* args */)     {         // code validate unit tests of send() passing in correctly (and won't have send anything.)     } } 

... , then, instead of calling 'sender.send' directly, pass in isender you're planning on using perform send. regular code pass in instance of sender; unit tests pass in instance of dummysender.

edit (to new info given)

that part imailsender? that's perfect.

first up, instead of hooking right 'sender', instead pass imailsender object send() functions additional argument. can write like:

public class unittestdummysender : imailsender {     public string fromaddressishouldget;     public string toaddressishouldget;     public string bodyishouldget;     public void send(string from, string to, string body)     {         // check make sure arguments passed in match properties     } } 

see how works? instead of calling send(), this:

// regular code: send(custlist, body, mynormalsenderclass);  // unit test code: unittestdummysender faker = new unittestdummysender(); // lines set faker properties email should work out send(myfakecustlist, body, faker); 

hope helps! :-)


Comments

Popular posts from this blog

PHP and MySQL WP -

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

go - golang pprof for c library code -