This is a migrated thread and some comments may be shown as answers.

Mocking SendMail Workflow Activity

4 Answers 118 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Steve
Top achievements
Rank 1
Steve asked on 22 Mar 2013, 05:16 PM
Hi folks, I am trying to mock the SendMail windows workflow activity.

In this default workflow, the SmtpClient calls SendAsync(), and without a callback, the workflow just hangs forever.  So obviously, i need to fake out SendAsync() so that no email is sent, but I also want to 'DoInstead' and trigger the SendComplete event.  Am I missing anything obvious in my code snippet below?


        public UnitTestProject()
        {
        Mock.Replace<SmtpClient>(x => x.SendAsync(Arg.IsAny<MailMessage>(), null)).In<SendMail>();    
        }


        [TestMethod]
        public void TestSendMail()
        {   
            var smtpClient = new SmtpClient(Arg.AnyString);            
            var args = new System.ComponentModel.AsyncCompletedEventArgs(null, false, null);
                        
            Mock.Arrange(() => smtpClient.SendAsync(Arg.IsAny<MailMessage>(), null))
                        .IgnoreArguments()
                        .IgnoreInstance()
                        .DoInstead(
                        () => Mock.Raise(
                                () => smtpClient.SendCompleted += null, args)
                        );   // not raising the event ...
       
                                                  
            var wit = new WorkflowInvokerTest(new SendMail
            {
                Body = "BodyString",
                IsBodyHtml = true,
                CC = "email@example.com",
                To = "email@example.com",
                From = "email@example.com",
                Sender = "email@example.com",
                Subject = "Unit testing"
            });            
                        
            wit.TestActivity();
            Mock.Assert(smtpClient);
        }       


        

4 Answers, 1 is accepted

Sort by
0
Steve
Top achievements
Rank 1
answered on 22 Mar 2013, 06:33 PM
Once I made the event public, I was able to mock it out as follows:


 Mock.Arrange(() => smtpClient.SendAsync(Arg.IsAny<MailMessage>(), null))
                     .IgnoreArguments()
                     .IgnoreInstance()
                     .DoInstead(() => sm.smtpClient_SendCompleted(null, args))
                     .OccursOnce();    

0
Steve
Top achievements
Rank 1
answered on 22 Mar 2013, 07:22 PM
Eh, I don't want to break encapsulation to unit test this activity.

Can you help me figure out why this throws a generic exception saying "Can't mock the expected event."

Mock.Arrange(() => smtpClient.SendAsync(Arg.IsAny<MailMessage>(), null))
                     .IgnoreArguments()
                     .IgnoreInstance()
                     .Raises( () => smtpClient.SendCompleted += null, args)
                     .OccursOnce();  
0
Steve
Top achievements
Rank 1
answered on 25 Mar 2013, 04:18 PM
My problem is related to raising events, so I created a more accurate thread here:

http://www.telerik.com/community/forums/justmock/general-discussions/cannot-raise-events.aspx


You can close/delete this thread.
0
Kaloyan
Telerik team
answered on 26 Mar 2013, 12:42 PM
Hi Steven,

I apologize for the late reply.

However, investigating your examples, I noticed that you will need to create a concrete mock to hold the certain arrange. Please check the following example, which is the same as yours with the only difference that "smtpClient" is a mock of the original "SmtpClient" class:
[TestMethod]
public void ShouldRaiseAnEventOnSendAsyncInvocation()
{
    var smtpClient = Mock.Create<SmtpClient>(Behavior.CallOriginal);           
    var args = new System.ComponentModel.AsyncCompletedEventArgs(null, false, null);
             
    Mock.Arrange(() => smtpClient.SendAsync(Arg.IsAny<MailMessage>(), null))
        .IgnoreArguments()
        .IgnoreInstance()
        .DoInstead(
        () => Mock.Raise(
            () => smtpClient.SendCompleted += null, args)); 
 
    smtpClient.SendAsync(new MailMessage(),null);
}
You could see that the above example does not throw the "Can't mock the expected event." exception and it behaves as expected.

To help you further, I must note that the "Mock.Replace" should be only used when your goal is to fake MsCorlib members, for everything else you should be using Mock.Create<T>(). You could read more about mocking MsCorlib members, here.

I hope this helps.

All the best,
Kaloyan
the Telerik team
Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
Tags
General Discussions
Asked by
Steve
Top achievements
Rank 1
Answers by
Steve
Top achievements
Rank 1
Kaloyan
Telerik team
Share this question
or