Mocking SendMail Workflow Activity

5 posts, 0 answers
  1. Steve
    Steve avatar
    13 posts
    Member since:
    Feb 2013

    Posted 22 Mar 2013 Link to this post

    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);
            }       


            
  2. Steve
    Steve avatar
    13 posts
    Member since:
    Feb 2013

    Posted 22 Mar 2013 Link to this post

    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();    

  3. DevCraft R3 2016 release webinar banner
  4. Steve
    Steve avatar
    13 posts
    Member since:
    Feb 2013

    Posted 22 Mar 2013 Link to this post

    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();  
  5. Steve
    Steve avatar
    13 posts
    Member since:
    Feb 2013

    Posted 25 Mar 2013 Link to this post

    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.
  6. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 26 Mar 2013 Link to this post

    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.
Back to Top
DevCraft R3 2016 release webinar banner