Static mocking behaviour is very confusing

2 posts, 0 answers
  1. David
    David avatar
    3 posts
    Member since:
    Sep 2017

    Posted 23 Aug 2019 Link to this post

    I am having a lot of trouble understanding the behaviour of static mocking. I have a static class with two static functions, each of which returns a string, I have a test class whose constructor calls both functions on the static class, and I have a set of tests that arrange only one of the static functions, and which call SetupStatic in various ways. The results are as follows:

    1. SetupStatic is not called at all: the arranged function uses the mock arrangement and gets the arranged return value, the other function calls the original - as expected;

    2. SetupStatic(MyType, Behavior.Strict) is called: the arranged function uses the mock arrangement and gets the arranged return value, the other function throws a "Called unarranged member on strict mock" exception - as expected;

    3. SetupStatic(MyType) is called (ie. default Behavior): the arranged function uses the mock arrangement and gets the arranged return value, the other function does not call the original and gets an empty string as the return value - unexpected;

    4. SetupStatic(MyType, Behaviour.Loose) is called: the arranged function uses the mock arrangement and gets the arranged return value, the other function does not call the original and gets null as the return value - doubly unexpected as the documented default value of Behavior is Loose;

    5. SetupStatic(MyType, Behaviour.RecursiveLoose) is called: the arranged function uses the mock arrangement and gets the arranged return value, the other function does not call the original and gets an empty string as the return value - unexpected;

    6. SetupStatic(MyType, Behavior.CallOriginal) is called: the arranged function uses the mock arrangement and gets the arranged return value, the other function calls the original - I'm not sure what I would expect for this;

    I am using JustMock version R2 2019 SP1.

    I would be grateful if someone could tell me if this is working correctly, and what the logic is behind this behaviour.

    Thanks

  2. Mihail
    Admin
    Mihail avatar
    263 posts

    Posted 26 Aug 2019 Link to this post

    Hello David,

    I will try to explain the differences between the behaviors with interfaces as it is a bit easier to grasp.
    Take for example the following code:
    public interface Foo
    {
        IBar Bar { get; set; }
    }
     
    public interface IBar
    {
        string StringProperty { get; set; }
    }

    When you create a mock of type Foo with Loose behavior, the members will act like stubs. With other words the members will return null for reference types and the default value for value types. This means that if you have a not arranged call to foo.Bar.StringProperty a NullReferenceException will be thrown because the Bar property will be null. Here a code representation:
    [TestMethod]
    [ExpectedException(typeof(NullReferenceException))]
    public void TestMethod1()
    {
        var foo = Mock.Create<Foo>(Behavior.Loose);
     
        var actual = foo.Bar.StringProperty; // the Bar property will be null
     
        Assert.IsNotNull(actual);
    }


    If you create the mock with RecursiveLoose behavior, the members will act like mocks. With other words the reference type members will return mocks and the default value for value types.

    The common between those two behaviors is that a non empty collection will be returned for all IEnumerables members. String would be such a member because it inherits IEnumerable<char>. In this sense a non empty IEnumerable<char> is empty string.
    This is the default behavior.

    If you create the mock with Strict behavior, any call to not arranged member will throw exception.

    If you create the mock with CallOriginal behavior, the call to any member will execute the original code. This is the only behavior where the original code will be executed 

    Here is a link to our documentation article where you can read more about the behaviors.

    The same rules are applicable for static classes as well.

    I hope this information is helpful.

    Regards,
    Mihail
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top