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
Hi,
I wonder if it is possible to automatic mocking child classes and store values in them.

Simple example for testing presenter in MVP projects.

    public interface ILabel
    {
        string Text { get; set; }
        bool Visible { get; set; }
    }

    public interface IView
    {
        ILabel LabelAdapter { get; }
    }

    public class Presenter
    {
        public IView View;
        public void SetLabel()
        {
            View.LabelAdapter.Text = "2";
            View.LabelAdapter.Visible = true;
        }
    }

    [TestFixture]
    public class Tests
    {
        [Test]    
        public void SetLabel_Test()
        {
            //arrange
            var presenter = new Presenter();
            var mockedView = Isolate.Fake.Instance<IView>();
                 //var mockedLabel = Isolate.Fake.Instance<ILabel>();
            presenter.View = mockedView;
                 //Isolate.WhenCalled(() => mockedView.LabelAdapter).WillReturn(mockedLabel);

            //act
            presenter.SetLabel();

            //assert
            Assert.AreEqual("2",presenter.View.LabelAdapter.Text);
            Assert.IsTrue(presenter.View.LabelAdapter.Visible);
        }
    }


When I uncomment two lines in test it works fine. But if view would has many controls I have to mock every control in test. When lines are commented I get info on first assert that:
Expected: "2" But was: <string>

Values set in tested methods are not store in ILabel mock. Why? Is it possible to achieve my testing purpose without this two commented lines?
br
tlucz
asked by tlucz (2.9k points)

8 Answers

0 votes
Hi tlucz,

What you are describing is a bug which we are already aware of; it happens at the intersection of two features that, when working together, will provide all the functionality you need according to your description.

Recursive Fakes are the default mode of operation when creating fake instances. When a method is called on a recursive fake, its return value is also faked recursively - this means that if it returns a value type (int, string, etc) then a basic value (0, "", etc) will be returned, and if it returns a reference type, it will return a recursive fake. This allows you to completely ignore whole call chains without assigning fake objects explicitly to every step in the chain.

True Properties is a feature that allows values set with property setters to be returned by property getters. This is exactly what you expect to happen in your example, and indeed it's what should happen. The bug here is that True Properties do not work well together with Recursive Fakes - actually, they work only on the first level of the fake (properties called directly from recursive fakes act as true properties), but not on deeper levels.

I will work to resolve this issue and send you a properly working patched version. In the meanwhile, you can replace the Assert statement with a statement on the property getter, with a verify statement that verifies the property setter was called with the correct argument:
 Isolate.Verify.WasCalledWithExactArguments(() => presenter.View.LabelAdapter.Text = "2"); 


Please write back here if this workaround works for you.

Thanks,
Doron
Typemock Support
answered by doron (17.2k points)
0 votes
Thanks for your answer and detailed explaining the problem. Your workaround works in this case but...

if I will change implementation of SetLabel:
public void SetLabel()
        {
            View.LabelAdapter.Text = "3";
            ///
            ///some calculating and conditions here
            /// 
            /// 
            View.LabelAdapter.Text = "2";
            View.LabelAdapter.Visible = true;
        }


I know that it is not the best solution to change label text property during method executing but this might be another property.

Then
Isolate.Verify.WasCalledWithExactArguments(()=>presenter.View.LabelAdapter.Text="3");

and
Isolate.Verify.WasCalledWithExactArguments(()=>presenter.View.LabelAdapter.Text="2");

passed the test.

So it is not solution for more complicated examples, because I'm interested in property value on the end of tested method.
br
tlucz
answered by tlucz (2.9k points)
0 votes
In this case, you can use DoInstead() as a workaround - DoInstead() defines alternate code to run instead of a method call. I suggest using it to replace the call to the property setter:
string lastValue;
Isolate.WhenCalled(() => {mockedView.LabelAdapter.Text = string.Empty}).DoInstead(x => lastValue = (string)x.Parameters[0]);


This will save the last value the setter was called with into lastValue, which you can later assert against.

Can you let me know if this works for you?

Thanks,
Doron
Typemock Support
answered by doron (17.2k points)
0 votes
Yes, that also works but it is workaround. And in my opinion it causes that test will be not easy readable to others. I think that tests should be as simple as possible because they are also example of our class usage, API to other team developers. So I prefer my solution with additionally mock child classes cause it is more readable:
//arrange
var mockedLabel = Isolate.Fake.Instance<ILabel>(); 
Isolate.WhenCalled(() => mockedView.LabelAdapter).WillReturn(mockedLabel); 
//assert
Assert.AreEqual("2",presenter.View.LabelAdapter.Text); 

than (kind of magic :) )
//arrange
string lastValue; 
Isolate.WhenCalled(() => {mockedView.LabelAdapter.Text = string.Empty}).DoInstead(x => lastValue = (string)x.Parameters[0]); 
//act
Assert.AreEqual("2", lastValue);


But when True Properties and Recursive Fakes will work together life will be easier so I'll wait for patched version. Thanks for your time and explanations. BTW: when patched version could be deployed?

br
tlucz
answered by tlucz (2.9k points)
0 votes
This issue's bug fix will be released with the next version of Isolator - sometime in the next few weeks. I will send you a patched installer before that, probably late this week or early next week.

Doron
Typemock Support
answered by doron (17.2k points)
0 votes
Hi,
Any information about patched version or date of release new version?
br
tlucz
answered by tlucz (2.9k points)
0 votes
Hi Tlucz,

The new version will be out next week but I'll send you the installer now via mail.
Please let me know if it solves the problem.
answered by ohad (35.4k points)
0 votes
Update: This issue was fixed on Typemock Isolator 5.3.4.
answered by dhelper (11.9k points)
...