Friday, August 15, 2008

Addicted to my 24" Monitor

Guess I am getting a bit too addicted to the extra real estate.  The code in my blog looks awful on smaller monitor/window.  Will have to go back and reformat I guess when I have time.

[Rhino] Mock Anomalies: SetupResult.For to Lambda - "No Dice"

I had probably jumped to some conclusions with my earlier post.  While it's true GenerateStub<T>() refuses to accomodate SetupResult, the below testcase passes:

[TestMethod]
public void GenerateStubAndSetupResult()
{
    //With GenerateStub() alone, SetupResult fails with
    //IDemo stub = (IDemo)MockRepository.GenerateStub<IDemo>();
    IDemo stub = new MockRepository().Stub<IDemo>();
 
    int j = 0;
 
    SetupResult
        .For<string>(stub.ReturnStringNoArgs())
        .Do((Func<string>)(() => { return (++j).ToString(); }));
 
    SetupResult
        .For<string>(stub.ReturnStringWithInt32Arg(300)).IgnoreArguments()
        .Do((Func<int, string>)((arg) => { return string.Format("000{0}", arg); }));
 
    stub.Replay();
    Assert.AreEqual("1", stub.ReturnStringNoArgs());
    Assert.AreEqual("2", stub.ReturnStringNoArgs());
    Assert.AreEqual("000400", stub.ReturnStringWithInt32Arg(400));
    Assert.AreEqual("000500", stub.ReturnStringWithInt32Arg(500));
} 

Let's take our previous code and rewrite it, using the lesson above:

[TestMethod]

public void TestSetupStubOnceCallMultipleTimes2()
{
    //IDemo partialStub = MockRepository.GenerateStub<IDemo>();
    IDemo partialStub = new MockRepository().Stub<IDemo>();
 
    //This line does not work unless I have called the above .Stub<IDemo>
    //partialStub
    //    .Stub<IDemo, string>((x) => { return x.ReturnStringWithInt32Arg(30); })
    //    .IgnoreArguments()
    //    .Do(
    //        (Func<int, string>)((arg) =>
    //        {
    //            return string.Format(
    //                "{0}{1}",
    //                new string('0', 6 - arg.ToString().Length), arg);
    //        })
    //    );
 
    //If I comment the above line out, it gives me this error on SetupResult below
    //Test method ThinkFarAhead.LearningMocking.Expectations.SetupResult2.TestRhinoAndMoq.Working threw exception:
    //System.InvalidOperationException: Invalid call, the last call has been used or 
    //no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)..
    //This error occurs both when I create the Stub using MockRepository.GenerateStub<IDemo>() or new MockRepository().Stub<IDemo>()
    //SetupResult.For((Action<IDemo>)(x => x.ReturnStringWithInt32Arg(30))).IgnoreArguments()
    //  .Do((Func<int, string>)((arg) =>
    //  {
    //      return string.Format(
    //          "{0}{1}",
    //          new string('0', 6 - arg.ToString().Length), arg);
    //  }
    //    ));
 
    SetupResult
        .For(partialStub.ReturnStringWithInt32Arg(20))
        .IgnoreArguments()
        .Do((Func<int, string>)((arg) =>
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            }
        ));
 
    partialStub.Replay();
    Assert.AreEqual("000020", partialStub.ReturnStringWithInt32Arg(20));
    Assert.AreEqual("000030", partialStub.ReturnStringWithInt32Arg(30));
    Assert.AreEqual("000040", partialStub.ReturnStringWithInt32Arg(40));
}

[Rhino] Mock Anomalies: Setup Stub Once Call Multiple Times - Must Call .Stub<T> and SetupResult

I was hooking up multiple times because otherwise it was giving me grief.  Here's the test that seems to work the way I intended (for setting up a stub method once and call it multiple times.

[TestMethod]
public void TestSetupStubOnceCallMultipleTimes()
{
    //IDemo partialStub = MockRepository.GenerateStub<IDemo>();
    IDemo partialStub = new MockRepository().Stub<IDemo>();
 
    //This line does not work unless I have called the above .Stub<IDemo>
    partialStub
        .Stub<IDemo, string>((x) => { return x.ReturnStringWithInt32Arg(30); })
        .IgnoreArguments()
        .Do(
            (Func<int, string>)((arg) =>
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            })
        );
 
    //If I comment the above line out, it gives me this error on SetupResult below
    //Test method ThinkFarAhead.LearningMocking.Expectations.SetupResult2.TestRhinoAndMoq.Working threw exception:
    //System.InvalidOperationException: Invalid call, the last call has been used or 
    //no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)..
    //This error occurs both when I create the Stub using 
    //MockRepository.GenerateStub<IDemo>() or new MockRepository().Stub<IDemo>()
    SetupResult.For((Action<IDemo>)(x => x.ReturnStringWithInt32Arg(30))).IgnoreArguments()
      .Do((Func<int, string>)((arg) =>
      {
          return string.Format(
              "{0}{1}",
              new string('0', 6 - arg.ToString().Length), arg);
      }
        ));
 
 
    partialStub.Replay();
    Assert.AreEqual("000020", partialStub.ReturnStringWithInt32Arg(20));
    Assert.AreEqual("000030", partialStub.ReturnStringWithInt32Arg(30));
    Assert.AreEqual("000040", partialStub.ReturnStringWithInt32Arg(40));
}

Thursday, August 14, 2008

Mocking Anomalies: Can't Override Non-Virtual Methods (Ans: Partial Stubs?)

The problem I am facing currently is that I and my team are working simultaneously on interdependent pieces of the system under development. My piece was depending on a piece of my colleague's and one of his methods was throwing a "NotImplementedException".

Wanted to mock just that method so I could proceed with testing my work.

Here's how the code looks in Rhino:

    1 using System;
    2 using Microsoft.VisualStudio.TestTools.UnitTesting;
    3 using Rhino.Mocks;
    4 
    5 namespace ThinkFarAhead.LearningMocking
    6 {
    7     [TestClass]
    8     public class TestRhinoAndMoq
    9     {
   10         [TestMethod]
   11         public void TestPartialMock()
   12         {
   13             Demo partialMock = new MockRepository().PartialMock<Demo>();
   14             partialMock
   15                 .Stub<Demo, string>(x => x.ReturnStringNoArgs())
   16                 .Do((Func<string>)delegate { return "somevalidstring"; });
   17 
   18             partialMock.Replay();
   19             Assert.AreEqual(partialMock.ReturnStringNoArgs(), "somevalidstring");
   20         }
   21 
   22         [TestMethod]
   23         public void TestPartialStub()
   24         {
   25             IDemo partialStub = MockRepository.GenerateStub<IDemo>();
   26             partialStub
   27                 .Stub<IDemo, string>(x => x.ReturnStringNoArgs())
   28                 .Do((Func<string>)delegate { return "somevalidstring"; });
   29 
   30             partialStub.Replay();
   31             Assert.AreEqual(partialStub.ReturnStringNoArgs(), "somevalidstring");
   32         }
   33     }
   34 
   35     public interface IDemo
   36     {
   37         string ReturnStringNoArgs();
   38         string ReturnStringWithInt32Arg(int arg);
   39     }
   40 
   41     public class Demo : IDemo
   42     {
   43         public virtual string ReturnStringNoArgs()
   44         {
   45             throw new NotImplementedException();
   46         }
   47 
   48         public string ReturnStringWithInt32Arg(int arg)
   49         {
   50             return string.Format("{0}{1}", new string('0', 6 - arg.ToString().Length), arg);
   51         }
   52     }
   53 }

As you can see both the tests pass. Let's remove 'virtual' from:

   45 public string ReturnStringNoArgs()

Now, as expected, TestPartialMock fails.

Test method ThinkFarAhead.LearningMocking.TestRhinoAndMoq.TestPartialMock threw exception: System.NotImplementedException: The method or operation is not implemented..

Oh yeah, we've been told that it's a constraint imposed by Castle Dynamic Proxy [actually CLR]. Hey, I don't want to fight the system, all I want is to wring the functionality I need from the framework.

Also, consider the below behaviour:

            System.Diagnostics.Debug.WriteLine(partialMock.ReturnStringWithInt32Arg(20)); // will print "000020" 
            System.Diagnostics.Debug.WriteLine(partialMock.ReturnStringWithInt32Arg(30)); // will print "000030" 

With stub, you will have to setup two different expectations: [I'm not sure I need to! I've posted this question on the forum. Will provide the link later]

    partialStub
        .Stub<IDemo, string>((Func<IDemo, string>)delegate(IDemo x) { return x.ReturnStringWithInt32Arg(20); })
        .IgnoreArguments()
        .Do((Func<int, string>)
            delegate(int arg)
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            }
        );
 
    partialStub
        .Stub<IDemo, string>((Func<IDemo, string>)delegate(IDemo x) { return x.ReturnStringWithInt32Arg(30); })
        .IgnoreArguments()
        .Do((Func<int, string>)
            delegate(int arg)
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            }
        );
 
    partialStub.Replay();
    System.Diagnostics.Debug.WriteLine(partialStub.ReturnStringWithInt32Arg(20)); // will return "000020"             
    System.Diagnostics.Debug.WriteLine(partialStub.ReturnStringWithInt32Arg(30)); // will return "000030" 

Even if I do not have to setup multiple times, once for each argument, if the logic is non-trivial, replicating the same logic on the Stub method would be VERY inconvenient. Not to mention dependencies if needed. Stub per Fowler's definition is supposed to just return "canned" responses right? [Aside: This is a classic example of theory superceded by common sense. If you're supposed to return "canned" responses, you better be prepared to anticipate each argument. Guess that's what Fakes do. We're trying to implement a 'Fake' by using Rhino's Stub. Oh, well, we're getting derailed by jargon now]

OK, where does it all lead to? Well, It seems we need a PartialStub [Jargon again? :)]. Hm...or is there a better way?

How about this: One that will delegate [not the C# one, the one that managers practice ;)] calls to the original object when no expectations are set. And override them when specified.

Let's define our "wanna be" syntax, shall we?

With Rhino:

        [TestMethod]
        public void TestPartialStub()
        {
            Demo demo = new Demo();
            IDemo partialStub = MockRepository.GenerateStub<IDemo>(demo);
            partialStub
                .Stub<IDemo, string>(x => x.ReturnStringNoArgs())
                .Do((Func<string>)delegate { return "somevalidstring"; });
 
            partialStub.Replay();
 
            //Route calls to the actual object 
            Assert.AreEqual(partialStub.ReturnStringWithInt32Arg(20), "000020");
            Assert.AreEqual(partialStub.ReturnStringWithInt32Arg(30), "000030");
 
            //Call the Stub override 
            Assert.AreEqual(partialStub.ReturnStringNoArgs(), "somevalidstring");
        }
With Moq:
        [TestMethod]
        public void TestPartialStubMoq()
        {
            Demo demo = new Demo();
            Mock<IDemo> repo = new Mock<IDemo>(demo);
            IDemo partialStub = repo.Object;
 
            repo.Expect<string>(x => x.ReturnStringNoArgs()).Returns("somestringbydefault");
            Assert.IsTrue(partialStub.ReturnStringWithInt32Arg(10), "000010");
            Assert.IsTrue(partialStub.ReturnStringNoArgs(), "somestringbydefault");
        }

I would like to add this functionality to both Rhino & Moq with both Ayende and Daniell asking me to contribute. Hope I'll get something done over the weekend. Let me know what you think.