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
I'm trying to create an array of mocked objects but I get a run time error on the second creation.

Here is my code:
      private FinancialInstrument MockedFI(String Name)
      {
         FinancialInstrument MockedFI = (FinancialInstrument)RecorderManager.CreateMockedObject<FinancialInstrument>();
         using (RecordExpectations recorder = new RecordExpectations())
         {
            string s = MockedFI.Name;
            recorder.Return(Name).RepeatAlways();
            double x = MockedFI.Price[0];
            recorder.Return(1.0).RepeatAlways();
            bool b = MockedFI.HasMatured(0);
            recorder.Return(false).RepeatAlways();
         }
         return MockedFI;
      }

      private AssetCollection NewCollection(Type CollectionType, string NameStub, Economy EconomyModel, double[] Unit)

      {
         FinancialInstrument[] Asset = new FinancialInstrument[Unit.Length];

         for (int i = 0; i < Unit.Length; i++)
            Asset[i] = MockedFI(NameStub + i.ToString());
...


When Unit.Length is 1, it creates the array. When it is 2, I get:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at ax.a(String A_0, Object A_1, Object A_2, Type& A_3, String A_4)
at TypeMock.MockManager.a(String A_0, String A_1, Object A_2, Object A_3, Boolean A_4)
at TypeMock.InternalMockManager.isMocked(Object that, String typeName, String methodName, Object methodParameters, Boolean isInjected)
at Models.TimeDependentValue`1..ctor(String Name, Model MyModel, CalculateTimeDependentValue CalculateTimestepValue, CalculateStartTimeDependentValue CalculateStartValue, Int32 HistoryLength) in TimeDependentValue.vb:line 90
at Models.FinancialInstrument..ctor(String Name) in FinancialInstrument.vb:line 126
at MockFinancialInstrument..ctor(String )

What am I doing wrong please?
asked by hiegunn (1.9k points)

7 Answers

0 votes
Hi,

I would say that my first suspects are the following lines:
double x = MockedFI.Price[0]; 
recorder.Return(1.0).RepeatAlways(); 

although it seems simple, what you have here is a chain of calls which I suspect involves a type from MSCorlib.

Can you try to run the same test without mocking those calls?
If it passes let me know and we can figure out how to work around this problem
answered by lior (13.2k points)
0 votes
Thanks.
I've modified the code:
            string s = MockedFI.Name;
            recorder.Return(Name).RepeatAlways();
            //double x = MockedFI.Price[0];
            //recorder.Return(1.0).RepeatAlways();
            bool b = MockedFI.HasMatured(0);
            recorder.Return(true).RepeatAlways();


This runs, so the problem lies within my indexed property call.

The indexed property is fairly complex in behaviour. It calls a delegate which calculates a value. It then caches that value. Future calls check to see if the cached value exists, if so the delegate is not called and the cached value returns.

I wonder if I should be mocking the delegate?
answered by hiegunn (1.9k points)
0 votes
I see.
I thought that Price returned an array of double.
Anyway in this case the real problem is the RepeatAlways.
Since it works only on the last method call in the chain(in this case the indexer) it ends up with an unmocked call that access the real data in the class which was not initialized.

In any case we can work around the problem like this:


PriceReturnClass mockPrice = MockedFi.Price;
recorder.Return(PreparedObject).RepeatAlways();
double x = Price[0];
Recorder.Return(1.0).RepeatAlways()
answered by lior (13.2k points)
0 votes
I get a compile error with PreparedObject. What is this please?

I've guessed at your meaning:
      private FinancialInstrument MockedFI(String Name)
      {
         double[] DummyPrice = new double[3];
         FinancialInstrument MockedFI = (FinancialInstrument)RecorderManager.CreateMockedObject(typeof(FinancialInstrument));
         using (RecordExpectations recorder = new RecordExpectations())
         {
            recorder.ExpectAndReturn(MockedFI.Name, Name).RepeatAlways();
            TimeDependentValue<Double> mockPrice = MockedFI.Price;
            recorder.Return(DummyPrice).RepeatAlways();
            double x = DummyPrice[0];  // *** line 77 with error
            recorder.Return(1.0).RepeatAlways();
            bool b = MockedFI.HasMatured(0);
            recorder.Return(true).RepeatAlways();
         }
         return MockedFI;
      }


Running this gives:
TypeMock.TypeMockException:
*** Method get_Price in type Models.FinancialInstrument cannot return System.Double[]
at TypeMock.RecordExpectations.Return(Object returnValue)
at Models.UnitTests.RebalancingUnitTest.MockedFI(String Name) in RebalancingUnitTest.cs:line 77
at TypeMock.MethodDecorator.CallRealMethod()
at TypeMock.MethodDecorator.f()
at TypeMock.MockManager.a(String A_0, String A_1, Object A_2, Object A_3, Boolean A_4, Object[] A_5)
at TypeMock.InternalMockManager.getReturn(Object that, String typeName, String methodName, Object methodParameters, Boolean isInjected, Object p1)
at Models.UnitTests.RebalancingUnitTest.MockedFI(String Name) in RebalancingUnitTest.cs:line 65[/code]
answered by hiegunn (1.9k points)
0 votes
I've managed to get further but with the original code. What I did was to change another mocked object later in the code. I've no idea why this should change. Let me do some more investigation and try to simplify the problem before getting back.

Thanks for the help so far.
answered by hiegunn (1.9k points)
0 votes
I seem now to be managing to mock the indexed properties :)

I'm now having problems with expectations - it may just be my misunderstanding though. Here is the core code that creates the mocked object:

private FinancialInstrument MockedFI(String Name)
      {
         FinancialInstrument MockedFI = (FinancialInstrument)RecorderManager.CreateMockedObject(typeof(FinancialInstrument));
         using (RecordExpectations recorder = new RecordExpectations())
         {
            string s = MockedFI.Name;
            recorder.Return(Name).RepeatAlways();
            Double x = MockedFI.Price[0];
            recorder.Return(1.0).RepeatAlways();
            bool b = MockedFI.HasMatured(0);
            recorder.Return(true).RepeatAlways();
         }
         return MockedFI;
      }


I create 9 mocked objects, 3 in 3 arrays then as a test, I run over each one to see if it returns 1.0;
      [Test]
      [VerifyMocks]
      public void TestAppropriateRebalancerCreated()
      {
         foreach(AssetCollection c in this.TestScheme.AssetPortfoliosModel)
         {
            for(int i=1; i < c.assetHoldings.Length; i++)
            {
               Assert.AreEqual(c.assets[i].Price[0], 1.0);
               //Double x = c.assetHoldings[i] / c.assets[i].Price[0];
            }
         }
      }

This gives:
TypeMock.VerifyException:
TypeMock Verification: Method Models.FinancialInstrument.get_Price() has 1 more expected calls
Method Models.FinancialInstrument.get_Price() has 1 more expected calls
Method Models.FinancialInstrument.get_Price() has 1 more expected calls
at TypeMock.MockManager.Verify()

When I uncomment the Double x - .../... I get:

TypeMock.VerifyException:
TypeMock Verification: Unexpected Call to Models.FinancialInstrument.get_Price()
at TypeMock.Mock.a(String A_0, Object[] A_1, Object A_2, Object A_3, Int32 A_4, Boolean& A_5, String A_6)

I don't understand why. I'm using Return(...).RepeatAlways so why in the first case is TypeMock expecting more calls when it has no idea how many there will be? The second case is similar - why does it think that more calls are unexpected?

Is there a long explanation of how expectations work? (I've looked at the code examples, the tutorial examples and the help reference but I am guessing at how it works and I need a proper explanation - I may be wrong in my guess.)
answered by hiegunn (1.9k points)
0 votes
Hi,

There are several questions Above, I will try to address them all as clearly as I can. let me know if I miss something or if something is not completely understood. So here goes:

1) you asked:
I get a compile error with PreparedObject. What is this please?
I meant PreparedObject as an object you need to prepare before the recording block. I havent posted to entire code for the test.
here it is (just in case):
  public FinancialInstrument MockedFI(String Name)
        {
             FinancialInstrument MockedFI = (FinancialInstrument)RecorderManager.CreateMockedObject<FinancialInstrument>(Constructor.NotMocked); 
             using (RecordExpectations recorder = new RecordExpectations()) 
             { 
                 string s = MockedFI.Name; 
                 recorder.Return(Name).RepeatAlways();
                 TimeDependentValue<Double> mockArray = MockedFI.Price;
                 recorder.ReturnDefaultImplementation().RepeatAlways();
                 double x = mockArray[0];
                 recorder.Return(1.0).RepeatAlways();
                 bool b = MockedFI.HasMatured(0); 
                 recorder.Return(false).RepeatAlways(); 
             } 
             return MockedFI; 
        } 

:!: Note how I bypassed the RepeatAlways issue by splitting the calls and using the ReturnDefaultImplementation(), which is good for cases when the actual return value is not interesting.

2) The error you get :
// *** line 77 with error

*** Method get_Price in type Models.FinancialInstrument cannot return System.Double[]

This happens since the return value of "Price" is not double[] type. If I read it correctly, the return value type is TimeDependentValue<Double>.

3) In your last post you reverted back to the original code. In this code you use "RepeatAlwyas" on the chained call:
MockedFI.Price[0];

(A Chain is a group of calls in which the return value from one call is used as the instanbce called by the next.
For example
a.b().c().d().e() is chain of 4 calls.
in this case the object returned by the call to Price is used by the call to its indexer - "[0]" )

As I stated before the RepeatAlways is only applied to the last call in the chain and in this case only to the call to [0] and not to the Price call (We consider this behavior as an issue and we intend on fixing this API to better answer the needs of the user)

You were right in your assumption that using RepeatAlways make the expectaion be repeated no matter how many times it was called (The problem here is that it was not applied to the right call)

4) you asked
The second case is similar - why does it think that more calls are unexpected?

The answer is related to the internal behaviour of the expectation in cases of calls with no expectations set on them (we call these "unexpected" calls). In general when dealing with concrete classes, all "unexpected" calls are diverted to the real code causing the real method to execute. However for interfaces & abstract classes we defined the behavior to be "Strict" i.e. all "unexpected" calls will reuslt in the verify exception being thrown. the reason is that for these cases we dont have a "real" code to execute.

5)
Is there a long explanation of how expectations work? (I've looked at the code examples, the tutorial examples and the help reference but I am guessing at how it works and I need a proper explanation - I may be wrong in my guess.)

You went over everything we have got. However I'm not sure what exactly what you need. If you have specific things you are looking for let me know ill try to check what can be done. Expectation by themselves behave very simply most of your guesses so far were tight on the spot. The mistakes were caused by our internal issues. (specifically the RepeatAlways which as I mentioned will be fixed)

I hope that this post has helped you understand more. If you have any more questions please let me know.
answered by lior (13.2k points)
...