chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
AddressObject newAddress = new AddressObject() { StreetAddress = "123 Main Street", ZipCode = "66204" };


Isolate.WhenCalled( () => mockUseCase.CreateAddressObject( "123 Main Street", "66204", out newAddress ) ).WithExactArguments().WillReturn( UseCaseStatus.Success );

Why, oh why does newAddress come back as NULL when I'm stepping through my code?

I want to have WithExactArguments **and** an out parameter that I can populate. How do I do that, please?
asked by jasongb (1.5k points)

13 Answers

0 votes
I should also add that when the use case is called from within the code, it looks something like this:

AddressObject addressObject = null;
RealUseCase realUseCase = new RealUseCase();
RealUseCaseStatus status = realUseCase.CreateAddressObject( streetAddress, zipCode, out addressObject );

Things work as long as I don't use .WithExactArbuments(), but I think that's hokey.
answered by jasongb (1.5k points)
0 votes
Hi,

I'll more info in order to understand the problem, can you post the full test code?
Also please tell me what version of the Isolator are you using.
answered by ohad (35.4k points)
0 votes
I downloaded TypeMock Isolator yesterday - so whatever version is currently available on your website...

Sorry for the lengthy code, but you asked for it :)

The following code is not exactly the code I'm working with, but it's self-contained and represents what I want to see when my code runs. This code can be pasted into Snippet Compiler and executed ( provided you've set it up with TypeMock ( http://www.paraesthesia.com/archive/2008/02/21/template-for-quick-typemock-testing.aspx ) ):

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using NUnit.Framework;
using TypeMock;
using TypeMock.ArrangeActAssert;

[TestFixture]
[VerifyMocks]
public class MyTestFixture
{
   [Test]
   public void MyTest()
   {
      IMyAddressUseCase mockUseCase = SingletonUseCase.Instance;
      
      MyAddressObject returnAddressObject = new MyAddressObject();
      returnAddressObject.StreetAddress = "123 Main Street";
      returnAddressObject.City = "Anytown";
      returnAddressObject.State = "CA";
      
      Isolate.WhenCalled( () => mockUseCase.ProcessAddress( "123 Main Street", "Anytown", "CA", out returnAddressObject ) ).WithExactArguments().
         WillReturn( MyAddressUseCaseStatus.Success );
      
      ACallingClass callingClass = new ACallingClass();
      MyAddressObject resultantObject = callingClass.CallTheUseCase( "123 Main Street", "Anytown", "CA" );
      Assert.IsNotNull( resultantObject, "ResultantObject is NULL" );
      Assert.AreEqual( "123 Main Street", resultantObject.StreetAddress );
   }
}

public class SingletonUseCase 
{
   private static IMyAddressUseCase instance;
   private SingletonUseCase() {}
   public static IMyAddressUseCase Instance
   {
      get
      {
         if ( instance == null )
         {            
            instance = Isolate.Fake.Instance<IMyAddressUseCase>();
         }         
         return instance;
      }
   }
}

public class MyAddressObject
{
   public string StreetAddress { get; set; }
   public string City { get; set; }
   public string State { get; set; }
}

public enum MyAddressUseCaseStatus
{
   Success,
   Failure
}

public interface IMyAddressUseCase
{
   MyAddressUseCaseStatus ProcessAddress( string streetAddress,
      string city, string state, out MyAddressObject myAddressObject );
}

public class MyAddressUseCase : IMyAddressUseCase
{
   public MyAddressUseCaseStatus ProcessAddress( string streetAddress,
      string city, string state, out MyAddressObject myAddressObject )
   {
      myAddressObject = new MyAddressObject();
      myAddressObject.City = city;
      myAddressObject.State = state;
      myAddressObject.StreetAddress = streetAddress;
      return MyAddressUseCaseStatus.Success;
   }
}

public class ACallingClass
{
   public MyAddressObject CallTheUseCase( string streetAddress, 
      string city, string state )
   {
      IMyAddressUseCase useCase = SingletonUseCase.Instance;
      MyAddressObject myAddressObject = null;
      MyAddressUseCaseStatus status = useCase.ProcessAddress( streetAddress,
         city, state, out myAddressObject );
      if ( status == MyAddressUseCaseStatus.Success )
         return myAddressObject;
      
      return null;
   }
}
answered by jasongb (1.5k points)
0 votes
You're probably wondering, 'Why the Singleton?'

We use the abstract factory pattern to generate our objects, so when ACallingClass executes, it calls a factory manager to create an instance of the use case. Outside of the test environment, the manager simply creates a new instance of the object. In the test environment, we use the Singleton so ACallingClass gets the mock object we created and 'arranged' in our test. This technique lets us avoid a redesign for dependency injection.

In this specific case, the actual code is involved in address validation for multiple addresses. As long as we use .WithExactArguments(), my expectations are that I can 'arrange' all of the outcomes I require, then execute the actual code and validate my results.
answered by jasongb (1.5k points)
0 votes
Hi,

First thanks for the detailed code, it is easier to see the problem that way :)
I'm afraid that we have a bug in the Isolator.
Using argument condition and out/ref parameter does not work.
As a work around you can use DoInstead that let you run your own logic against the arguments so faking mockUseCase.ProcessAddress will look like this:
Isolate.WhenCalled(() => mockUseCase.ProcessAddress("123 Main Street", "Anytown", "CA", out returnAddressObject)).
    DoInstead(context =>
            {
                string street = context.Parameters[0] as string;
                string city = context.Parameters[1] as string;
                string state = context.Parameters[2] as string;

                context.Parameters[3] = returnAddressObject;

                if (street == "123 Main Street" && city == "Anytown" && state == "CA")
                {
                    return MyAddressUseCaseStatus.Success;
                }
                return MyAddressUseCaseStatus.Failure;
            });


Please let me know if it helps.
answered by ohad (35.4k points)
0 votes
I guess I have several questions:

1) Just wanted to confirm: When you don't use .WithExactArguments(), any of the setup you've performed with .WhenCalled() will effectively be queued. I added another address to my code, then called .WhenCalled() to setup expectation A and called .WhenCalled() to setup expectation B. When I tested A and then B, the return values matched what I'd set up. When I tested B and then A, my test failed because the first call returned test results A.

2) We're thinking of spending about $17k on licenses for your software, and the bug you've described seems pretty significant. Out/ref parameters are core to the majority of our use cases. I understand that there's a workaround, but that seems like a lot of work compared to the way your software is supposed to function. What's the ETA on fixing that bug? Is it a priority? How long has that been around?

Thanks.
answered by jasongb (1.5k points)
0 votes
Hi,

1. Yes, when you set few expectations on the same method the behavior is queued. This best explained by a simple example:
public class Foo
{
    public int Bar()
  {
      return 0;
  }
}
 
[Test]
public void Test()
{
  var fake = Isolate.Fake.Instance<Foo>();
  Isolate.WhenCalled(() => fake.Bar()).WillReturn(1);
  Isolate.WhenCalled(() => fake.Bar()).WillReturn(2);
  Isolate.WhenCalled(() => fake.Bar()).WillReturn(3);
 
  Assert.AreEqual(1, fake.Bar());
  Assert.AreEqual(2, fake.Bar());
  // The last WhenCalled becomes the default from now on all calls will return 3
  Assert.AreEqual(3, fake.Bar());
  Assert.AreEqual(3, fake.Bar());
}


2. I'll talk to our product manager and let you know. It's national holiday here so you can expect an answer at beginning of next week.
answered by ohad (35.4k points)
0 votes
Thanks so much!... I hope you get to enjoy the holiday too.
answered by jasongb (1.5k points)
0 votes
Hi

OK, the fix will be ready in a few weeks. I'll update you once it's ready.
answered by ohad (35.4k points)
0 votes
Hi!...

I wanted to see if the fix is available yet; I'll be doing some training for my colleagues and would like to avoid .DoInstead().

Thanks!
answered by jasongb (1.5k points)
...