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
LoggingSqlCommand is just a wrapper around SqlCommand that does logging on 'Execute' methods...nothing fancy...when we 'CreateCommand' in are ADO.NET code we are getting back one of these objects.

So here's the 'mocking' - I want CallOriginal on the LoggingSqlCommand because later I want to check to make sure a parameter in the Parameters collection is present (if faked, can't do that).

SqlConnection mockConnection = Isolate.Fake.Instance<SqlConnection>(Members.CallOriginal);
         Isolate.Swap.NextInstance<SqlConnection>().With(mockConnection);
         Isolate.WhenCalled(() => mockConnection.Open()).IgnoreCall();
         Isolate.WhenCalled(() => mockConnection.Close()).IgnoreCall();

         LoggingSqlCommand mockCommand = Isolate.Fake.Instance<LoggingSqlCommand>(Members.CallOriginal);*****
         Isolate.Swap.NextInstance<LoggingSqlCommand>().With(mockCommand);
         Isolate.WhenCalled(() => mockCommand.ExecuteScalar()).WillReturn(-1);


Problem is when I create LoggingSqlCommand fake (where I have the *****), the constructor is being called which throws a null reference exception... why is the constructor being called?

      public LoggingSqlCommand(SqlCommand cmd)
      {
         if (cmd == null)
         {
            throw new ArgumentNullException("cmd");
         }
         _internalCommand = cmd;
      }


So if I use the default behavior I'm fine...but that won't help me determine if a parameter is present in the Parameters collection because now the Parameters collection is fake.
asked by boo (21.8k points)

8 Answers

0 votes
Brian,

First let's see what happens. When you use Fake.Instance with CallOriginal, the constructor gets call. Always. So the objected is created, and the parameter is null and you get the ArgumentException.

How to avoid this? You can create a fake SqlCommand, and pass it to the constructor of LoggingSqlCommand (new LoggingSqlCommand(fakeCommand))

You can use Isolate.WhenCalled and Isolate.Verify on everything you create in your test also ("live" object) so you can do this also on the LoggingSqlCommand.

Can you post the code that you want to verify?
answered by gilz (14.5k points)
0 votes
Would it be possible to just have an overload of Instance<T>(Members, param args) that you would pass the arguments too?
answered by boo (21.8k points)
0 votes
Hi Brian,

I've looked at the example code you've posted and I'm a bit confused.
First you create a fake instace using "CallOriginal", it seems unnecessary to me mainly because you do not need to create a fake object to use swap & whencalled, and on top of that you also want to call a specific c'tor when creating the new object.

Is there a reason you need to create a fake instance?
answered by dhelper (11.9k points)
0 votes
If I've specified 'CallOriginal' with my fake I would expect calls to 'Open' and 'Close' to actually do something unless on those methods I said to 'IgnoreCall', but I want all other calls on the object that happen within the method I'm testing to call the original.
answered by boo (21.8k points)
0 votes
So why don't you create an actual instance of LoggingSqlCommand with fake arguments and use "WhenCalled" and "Swap.NextInstance" to set the fake behavior?

Am I missing something?
answered by dhelper (11.9k points)
0 votes
That makes sense. Thanks
answered by boo (21.8k points)
0 votes
Still having problem, and I think it has to deal with here https://www.typemock.com/community/viewtopic.php?t=1177 where you say SwapNextInstance swaps behavior not references (which is very non-intuitive by the way; based upon what you say it should be SwapBehaviorOnNextInstance - what you describe seems to be the functionality of 'CallsOn' and if the two methods work the same what would be the difference?)
answered by boo (21.8k points)
0 votes
Gil,

consider the following two examples:
Mock mock = MockManager.Mock<MyClass>(Constructor.NotMocked);

and
MyClass fake = Isolate.Fake.Instance<MyClass>(Members.CallOriginal);
Isolate.Swap.NextInstance<MyClass>().With(fake);



There is small and subtle difference here. (which relates to the intention of the test writer)
while in the first example no actual ctor will be executed (not until the next instance is created). In the second example a real ctor will be executed when creating the fake object.
Since the fake is created with the intention of using it to swap something (AKA future mock), the writer usually doesnt need the ctor to be activated at that point of time.
:idea: what might help in this situation is the ability to pass arguments for the ctor at this point of time.
answered by error (6.6k points)
...