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
I am struggling to mock a particular method:

internal interface IEditScreen
{
   void ShowWindow(
      Customer cust, int position, bool allowDelete, bool allowSave,
      out EN_EDIT_RESULT buttonResult, 
      out string customerId, 
      out int positionResult, 
      out int reportResults);
}

I want to call a method "Controller.ClickOnCustomer(2)" and:
1) Verify Controller calls ShowWindow()
2) Verify the values of position, allowDelete, and allowSave
3) Ignore what particular instance of cust was passed-in
4) Return certain values for the out parameters
5) Test some state after the ShowWindow() call was made.

I know how to do #1, and #5. But not #2,#3, and #4. Here is the syntax I used with Moq:

EN_EDIT_RESULT result = EN_EDIT_RESULT.SAVE;
string customerId = "";
int positionResult = 2;
int reportResults = 0;

_mockScreen.Setup(
   screen => screen.ShowWindow(
   It.IsAny<Customer>(), 
   2, false, true,
   out result, out customerId, out positionResult, out reportResults)
);


How Moq handles this:
The Setup() method in Moq implicitly assumes .WithExactArguments(). The It.IsAny<> allows me to disregard the instance of Customer that was provided. I do this because Controller.ClickOnCustomer(2) creates a Customer object in this case. Now, I could probably find a way to override that constructor so I know the instance of Customer that I will get. But I haven't gone that far, and I really don't want to do that unless I must.

How to do this in TypeMock?
1) Can I use .DoInstead() and write a method body that verifies just the arguments I want to verify, and returns the out parameters I require? I am not sure how to use the DoInstead(), and it became overwhelming when I included out parameters.
2) I did Isolate.Swap.CallsOn + created another class that implements ShowWindow() the way I want. This worked, but making that class largely defeats the purpose of a mock object framework.

Goal:
I will probably be testing a dozen permutations of this call. My goal is to ensure that Controller.ClickOnCustomer() passes the right arguments in each situation, and that it does the correct state updates based on what ShowWindow() returns. The state verification stuff is no problem though.
asked by MobyDisk (3.6k points)

6 Answers

0 votes
I tried the following, but the out parameters aren't working, and I am limited in how many parameters I can use:
EN_EDIT_RESULT result = EN_EDIT_RESULT.SAVE;
string customerId = "";
int positionResult = 2;
int reportResults = 0;

Isolate.WhenCalled<int>(
        (position, allowDelete, allowSave) => _mockView.ShowWindow(
        null, position, allowDelete, allowSave, out result, out customerId, out positionResult, out reportResults)
    ).AndArgumentsMatch(
        (position, allowDelete, allowSave) => (position==2 && allowDelete==false && allowSave==true)
    );

That lets me verify up to 3 arguments (just enough) using an expression. But when the method returns, the out parameters all have uninitialized values (null for reference types like the string, 0 for enums or integers).

That isn't what TypeMock is supposed to be doing, according to:
http://msmvps.com/blogs/paulomorgado/archive/2008/10/06/faking-output-parameters-with-typemock-isolator.aspx
answered by MobyDisk (3.6k points)
0 votes
I seems we have an issue when using Argument Matching and out parameters. I will report this issue to our development team an let you know when we have a patch that fix it.
Until then I'll like to point out two things:
1. Setting out and ref parameters work when not using argument matching (the examples in the post you're referring to)
2. You can use up to 10 different arguments when when using argument matching - we've decided to show only 5 because we didn't want to "spam" the IDE intellisense.
answered by dhelper (11.9k points)
0 votes
Thanks for the feedback and the bug confirmation. Two things:

1) What workaround would you suggest using in the mean time? I could just use a return structure instead.
2) If we were not on an evaluation version, I would ask if there is a bug number we could track this with. Is this the kind of thing that takes days, weeks, or months?
answered by MobyDisk (3.6k points)
0 votes
I eliminated the out parameters, but now I get an exception from within TypeMock:

I have changed the method to return a class instead of using out parameters. The method signature was:
void ShowWindow(
   Customer cust, int position, bool allowDelete, bool allowSave,
   out EN_EDIT_RESULT buttonResult,
   out string customerId,
   out int positionResult,
   out int reportResults); 
but it is now:
WindowReturn ShowWindow(
   Customer cust, int position, bool allowDelete, bool allowSave); 

So I can do this in my unit test:
WindowReturn ret = new WindowReturn()
{
    ButtonResult = EN_EDIT_RESULT.SAVE,
    CustomerIdResult = "",
    PositionResult = 2,
    ReportResults = 0
};
And I unit test it like this:
** NOTE: The line below should be "less than", int, bool, bool, WindowReturn "greater than" but the forum editor is chopping off my generic arguments
Isolate.WhenCalled<int>(
        (position, allowDelete, allowSave) => _mockScreen.ShowWindow(
        null, position, allowDelete, allowSave)
    ).AndArgumentsMatch(
        (position, allowDelete, allowSave) => (position==2 && allowDelete==false && allowSave==true)
    ).WillReturn(ret);
But when I run the test I get the following error:
Test method MyNamespace.ScreenTest.Test_Click_Empty threw exception:  System.NullReferenceException: Object reference not set to an instance of an object..
With a call stack that starts with my Isolate.WhenCalled<> line shown above and then goes into obfuscated TypeMock stuff. I have verified that _mockScreen and ret are not null at the time. I also tried changing the Customer (first parameter) to a non-null value and I still get the error.

(Do you want me to open another forum thread for this? Is it a separate issue at this point?)
answered by MobyDisk (3.6k points)
0 votes
I confirmed that this does not happen if I remove the argument matching. The following does not throw the exception:
Isolate.WhenCalled(
        () => _mockView.ShowWindow(null, 2, true, false)
    ).WillReturn(ret);
answered by MobyDisk (3.6k points)
0 votes
Thank you for the extensive issue report - I'll add this information to our tracking system and let you know when we have this issue resolved
answered by dhelper (11.9k points)
...