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
0 votes
Seems the library doesn't like this particular syntax of creating an object on the fly:

Fails: Cannot return a value for CustomerManager.GetCustomer() because no value was set. use recorder.Return(). Fails in recording block.
         using (RecordExpectations recorder = new RecordExpectations())
         {
            CustomerManager_Accessor.GetCustomer(new SearchObject());
            recorder.Return( new Customer() { LastName = "DOE" });
         }



Passes: Same thing, just creating before Return is called:
         using (RecordExpectations recorder = new RecordExpectations())
         {
            Customer expectedReturn = new Customer() { LastName = "DOE" };
            CustomerManager_Accessor.GetCustomer(new SearchObject());
            recorder.Return(expectedReturn);
         }


Is this expected behavior or is this possibly from the use of property initializers?
asked by boo (21.8k points)

5 Answers

0 votes
Hi Brian,

First - why the first one doesn't work (which is a bug :oops: ). Let's look at the IL that is created (thanks to Reflector):
[TestMethod]
public void UnitTestThatFails()
{
    using (RecordExpectations recorder = new RecordExpectations())
    {
        CustomerManager.GetCustomer(new SearchObject());
        Customer <>g__initLocal1 = new Customer();
        <>g__initLocal1.LastName = "DOE";
        recorder.Return(<>g__initLocal1);
    }
}


As you can see, due to the code generation, the Return gets separated from GetCustomer, which creates the problem you see.

However, that's not all. If you verify or assert on the test that passes, you'll fail also. This is because the initialization inside the recording block affects assignments to future objects that are initialized differently.

The best workaround for this is to get this line:

Customer expectedReturn = new Customer() {LastName = "DOE"};
using (RecordExpectations recorder = new RecordExpectations())
{
    CustomerManager.GetCustomer(new SearchObject());
    recorder.Return(expectedReturn);
}


outside from the recording block. The recording mechanism does not get confused, and everything works corretly.[/b]
answered by gilz (14.5k points)
0 votes
You might want to try the new AAA APIthat is created to solve these problems.

CustomerManager_Accessor faked = Isolate.Fake.Instance<CustomerManager_Accessor>();

Isolate.WhenCalled(
  () => CustomerManager_Accessor.GetCustomer(new SearchObject()))
  .WillReturn(new Customer() { LastName = "DOE" });
answered by eli (5.7k points)
0 votes
Gil - thanks - but now I'm more confused on 'Verify'. Let's see if I get this straight - the code got injected obviously because the test passed (otherwsie I wouldn't got a NotImplementedException because GetCustomer throws one), my Assert later just check for a non-null return - and maybe that's why it passes? But then your saying if I called Verify - which as I understand just verifies that 'GetCustomer' was called would fail? When I get home I'll have to check that out.

Also, something that has been driving me nuts - I can't find the 'modified' code in Reflector. After reading about the engine I thought Typemock was maybe just working in memory and not a static weaver (I think that's the right terminology?) - but then you have an example of the modified IL? I've looked in the bin folder for the test project, and the test output. (I use MSTest projects).

Eli -'CustomerManager' is a static class...can't create an instance of static class - or am I misunderstanding what you're saying?

I know I've asked a million questions the past week, so thanks again for the patience and help.
answered by boo (21.8k points)
0 votes
Hi Brian,

If CustomerManager is a static class, you're correct - you can't create an instance. We are addressing APIs for statics as we speak :lol:

The code from reflector is the test code. Isolator only works at runtime, so there's no way to use reflector on that output. But if you look at your test code in reflector that's what you'll see. So the generated code I'm talking about is there because of the C# compiler, not Isolator's.

And, please, keep asking questions - that's what we're here for. :D
answered by gilz (14.5k points)
0 votes
Hi Brian,

Just to add some clarification.
The Isolator engine (the AOP part) is done (as Gil said) during runtime. We use the Profiler APi's in order to inject code during the JIT process done by the CLR.

The isolator is not a "Static" Weaver (i.e. the weaving is not done during compilation, but a "Dynamic" one (i.e. it is done during runtime).
The modification of the IL you see is done by the new 2008 framework compiler and is not part of the isolator product.
In fact, most of the new C# syntax (extension methods, anonymous types, LINQ syntax etc.) is based on compilation "tricks". If you will open such code using the reflector you can see how this is done.

:!: one more tip. Most "Static" profilers I have encountered create an alternative dll on which their code modification is done. So when you try searching for their modification just be sure to open the "right" dll.
answered by lior (13.2k points)
...