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 create a fake for
IDbAccessor
which then is injected inside business rules via property.
var bizRules = new BizRules();
bizRules.DbAccessor = fakeAccessor;

When I write
Isolate.WhenCalled(()=> bizRules.DbAccessor.GetResult(...)).WithExactArguments().WillRerurn(value);

everything works fine. but...if bizRules are part of another object:
Isolate.WhenCalled(()=> someObj.BizRules.DbAccessor.GetResult(...)).WithExactArguments().WillRerurn(value);

null value is returned instead of expected value.

typemock version 7.5.2.0
asked by voroninp (6.3k points)

3 Answers

0 votes
Seems like TypeMock expects first accessed member to be a fake instance.
Isolate.WhenCalled( () => fake.DoSomething())

So it cannot understand correctly the following:
Isolate.WhenCalled( () => prop1.prop2.prop3.fake.DoSomething())


Moreover it accepts an Action type instead of ExpressionTree<Action> so I suppose it works at a lower level and uses IL analysis.

I'd appreciate having additional method for the described use case:
Isoalte.WhenCalled<T>(Func<T> getFake, Action<T> call)

then
Isoalte.WhenCalled<T>(() => prop1.prop2.prop3.fake, fake => fake.DoSomething())
answered by voroninp (6.3k points)
0 votes
Hi,

The chained whencalled is used to define a behavior on a the full sequence of calls. But it doesnt matter
if the first object is faked or real. For example, take a look at this:

        public interface IMyInterface
        {
            int ReturnFive();
        }

        class Container
        {
            public IMyInterface Logger { get; set; }
        }
        
        [TestMethod, Isolated]
        public void Test()
        {
            var fake = Isolate.Fake.Instance<IMyInterface>();
            var real = new Container();
            real.Logger = fake;

            Isolate.WhenCalled(() => real.Logger.ReturnFive()).WillReturn(1);

            Assert.AreEqual(1, real.Logger.ReturnFive());
        }


In this example the ReturnFive() behavior is set only for calls coming from real.Logger.

If on the other hand the logger would have been saved to another container, then setting behavior on one
chain wouldn't affect the other chain. For example:

        [TestMethod, Isolated]
        public void Test2()
        {
            var fake = Isolate.Fake.Instance<IMyInterface>();
            var real = new Container();
            real.Logger = fake;

            var real2 = new Container();
            real2.Logger = fake;

            Isolate.WhenCalled(() => real.Logger.ReturnFive()).WillReturn(1);

            Assert.AreEqual(1, real.Logger.ReturnFive());
            Assert.AreEqual(0, real2.Logger.ReturnFive());
        }



To set the behavior on the fake, without regard from where its originated, then you need to
extract it first to its own variable:


        [TestMethod, Isolated]
        public void Test3()
        {
            var fake = Isolate.Fake.Instance<IMyInterface>();
            var real = new Container();
            real.Logger = fake;

            var real2 = new Container();
            real2.Logger = fake;

            var extractedFake = real.Logger;
            Isolate.WhenCalled(() => extractedFake.ReturnFive()).WillReturn(1);

            Assert.AreEqual(1, real.Logger.ReturnFive());
            Assert.AreEqual(1, real2.Logger.ReturnFive());
        }



I guess we can add an API that would extract the fake and set the behavior
but it seems to be not very readable. You can for example implement the following in
a helper class:

public IPublicNonVoidMethodHandler<T2> MyWhenCalled<T,T2>(T fake, Func<T, Func<T2>> rec)
        {
            return Isolate.WhenCalled(rec(fake));
        }


and then use it in your code:

            MyWhenCalled<IMyInterface, int>(c1.Logger, f => () => f.ReturnFive()).WillReturn(1);


But then take care to do it to the other overloads of WillReturn
answered by yoel (1.9k points)
0 votes
Thanks for the idea for the extension method.

But in the way it is required
T v=> () => v.ReturnSomething()
, compiler cannot deduce types and requires them explicitly inside <>. :(
answered by voroninp (6.3k points)
...