This is a migrated thread and some comments may be shown as answers.

How can I mock multiple instances of a struct?

5 Answers 548 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Timo
Top achievements
Rank 1
Timo asked on 10 Apr 2020, 06:19 AM

I put out a question on stackoverflow, but did not get any response. So let me link it here: https://stackoverflow.com/questions/61074264/how-can-i-mock-multiple-instances-of-a-struct

For convenience a copy of the text:

 

I have a `struct` that I want to mock. In a more complex test I need several instances of this struct, each with it's own behavior. To facilitate this, I've created a helper method.

    private MyStruct CreateMock(string toString) {
        var mock = Mock.Create<MyStruct>();
        Mock.Arrange(() => mock.toString()).Returns(toString);
        return mock;
    }

When I debug a test where this method is called multiple times, it appears as if the `Arrange` call is overwritten for ALL instances of the struct (or maybe I am using struct mocking instead of instance mocking?). 

I've tried:

    mock.Arrange(m => m.toString()).Returns(toString); // Using Helpers assembly, note the lowercase m at the start of the line.

But to no avail. How can I get multiple instances of a struct?

I'm using: 
Microsoft Visual Studio Enterprise 2017 
Version 15.9.17
VisualStudio.15.Release/15.9.17+28307.905
Microsoft .NET Framework
Version 4.8.03761

Installed Version: Enterprise

JustMock   2020.1.219.1
Telerik JustMock Extension.

**Example added**:
```
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Telerik.JustMock;
using Telerik.JustMock.Helpers;

namespace JustMockFramework
{
    public struct MyStruct
    {
        public readonly string Id;

        public MyStruct(string id)
        {
            Id = id;
        }

        public new string ToString()
        {
            return "Never read me!";
        }
    }

    [TestClass]
    public class MWE
    {
        [TestMethod]
        public void TestSimpleStruct()
        {
            var simpleTest = new MyStruct("1");

            Assert.AreEqual("Never read me!", simpleTest.ToString());
        }

        [TestMethod]
        public void TestMockOfStruct()
        {
            var mock = Mock.Create<MyStruct>();
            Mock.Arrange(() => mock.ToString()).Returns("Read me!");

            Assert.AreEqual("Read me!", mock.ToString());
        }

        [TestMethod]
        public void TestTwoMocksOfStruct()
        {
            var firstMock = Mock.Create<MyStruct>();
            Mock.Arrange(() => firstMock.ToString()).Returns("Read me!");

            var secondMock = Mock.Create<MyStruct>();
            Mock.Arrange(() => secondMock.ToString()).Returns("Read me too!");

            Assert.AreEqual("Read me!", firstMock.ToString()); // Fails with "Read me too!"
            Assert.AreEqual("Read me too!", secondMock.ToString());
        }

        [TestMethod]
        public void TestTwoMocksOfStructCreatedInHelper()
        {
            var firstMock = CreateMockOfStruct("Read me!");

            var secondMock = CreateMockOfStruct("Read me too!");

            Assert.AreEqual("Read me!", firstMock.ToString()); // Fails with "Read me too!"
            Assert.AreEqual("Read me too!", secondMock.ToString());
        }

        private MyStruct CreateMockOfStruct(string toString)
        {
            var mock = Mock.Create<MyStruct>();
            Mock.Arrange(() => mock.ToString()).Returns(toString);
            return mock;
        }

        [TestMethod]
        public void TestTwoMocksOfStructCreatedInHelperWithHelper()
        {
            var firstMock = CreateMockOfStructWithHelper("Read me!");

            var secondMock = CreateMockOfStructWithHelper("Read me too!");

            Assert.AreEqual("Read me!", firstMock.ToString()); // Fails with "Read me too!"
            Assert.AreEqual("Read me too!", secondMock.ToString());
        }

        private MyStruct CreateMockOfStructWithHelper(string toString)
        {
            var mock = Mock.Create<MyStruct>();
            mock.Arrange((m) => m.ToString()).Returns(toString);
            return mock;
        }
    }
}
```

 

5 Answers, 1 is accepted

Sort by
0
Ivo
Telerik team
answered on 14 Apr 2020, 01:23 PM

Hello Timo,

The behavior is desired and it caused by the different expectation matching based on the target mock type. Structures are value types, so on the acting phase, the particular expectation would be matched by comparing instances by value, not by reference.

Please consider changing the code  in the following way:

public struct MyStruct
{
    public readonly string Id;

    public MyStruct(string id)
    {
        Id = id;
    }

    public override string ToString()
    {
        return "Never read me!";
    }
}

[TestClass]
public class MWE
{
    [TestMethod]
    public void TestSimpleStruct()
    {
        var simpleTest = new MyStruct("1");

        Assert.AreEqual("Never read me!", simpleTest.ToString());
    }

    [TestMethod]
    public void TestMockOfStruct()
    {
        var mock = Mock.Create<MyStruct>("1");
        Mock.Arrange(() => mock.ToString()).Returns("Read me!");

        Assert.AreEqual("Read me!", mock.ToString());
    }

    [TestMethod]
    public void TestTwoMocksOfStruct()
    {
        var firstMock = Mock.Create<MyStruct>("1");
        Mock.Arrange(() => firstMock.ToString()).Returns("Read me!");

        var secondMock = Mock.Create<MyStruct>("2");
        Mock.Arrange(() => secondMock.ToString()).Returns("Read me too!");

        Assert.AreEqual("Read me!", firstMock.ToString()); // Fails with "Read me too!"
        Assert.AreEqual("Read me too!", secondMock.ToString());
    }

    [TestMethod]
    public void TestTwoMocksOfStructCreatedInHelper()
    {
        var firstMock = CreateMockOfStruct("1", "Read me!");
        var secondMock = CreateMockOfStruct("2", "Read me too!");

        Assert.AreEqual("Read me!", firstMock.ToString()); // Fails with "Read me too!"
        Assert.AreEqual("Read me too!", secondMock.ToString());
    }

    private MyStruct CreateMockOfStruct(string id, string toString)
    {
        var mock = Mock.Create<MyStruct>(id);
        Mock.Arrange(() => mock.ToString()).Returns(toString);
        return mock;
    }

    [TestMethod]
    public void TestTwoMocksOfStructCreatedInHelperWithHelper()
    {
        var firstMock = CreateMockOfStructWithHelper("1", "Read me!");
        var secondMock = CreateMockOfStructWithHelper("2", "Read me too!");

        Assert.AreEqual("Read me!", firstMock.ToString()); // Fails with "Read me too!"
        Assert.AreEqual("Read me too!", secondMock.ToString());
    }

    private MyStruct CreateMockOfStructWithHelper(string id, string toString)
    {
        var mock = Mock.Create<MyStruct>(id);
        mock.Arrange((m) => m.ToString()).Returns(toString);
        return mock;
    }
}

I hope the provided information answers your question. If you need further assistance do not hesitate to write us back.

Regards,
Ivo
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Timo
Top achievements
Rank 1
answered on 17 Apr 2020, 12:20 PM

Ivo, thank you for your answer. It took me a while to spot the differences, but you're passing in a constructor argument to the Mock.Create calls, which I did not right?

Unfortunately my trial period has ended, so I'm unable to check you solution at this time. 

0
Ivo
Telerik team
answered on 21 Apr 2020, 10:03 AM

Hello Timo,

Exactly, I am using additional parameters passed to MyStruct constructor in Mock.Create, which results in different values. Regarding the trial period, I will contact our sales department and ask them to extend it on your behalf, so you could be able to complete the evaluation.

It was pleasure to assist you. Have a great day.

Regards,
Ivo
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Timo
Top achievements
Rank 1
answered on 22 Apr 2020, 01:50 PM

Hello Ivo,

Thank you for reaching out to the sales department. They have graciously extended my trial license. I was able to verify your examples and indeed the problem is fixed.

Thanks for your support!

 

Regards,

Timo

0
Ivo
Telerik team
answered on 23 Apr 2020, 08:28 AM

Hello Timo,

I am glad to hear that the issue you were facing is now resolved and look forward to seeing you as a happy customer.

Regards,
Ivo
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
Tags
General Discussions
Asked by
Timo
Top achievements
Rank 1
Answers by
Ivo
Telerik team
Timo
Top achievements
Rank 1
Share this question
or