Reputation: 2242
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;
}
}
}
Edit: Cross posted
I've cross posted this question on the Telerik JustMock forum
Edit: License extended
My trial license was graciously extended. I've updated the answer to reflect this.
Upvotes: 1
Views: 428
Reputation: 2242
As described in the question, I cross posted the question and got an answer there.
It all boils down to value VS reference comparisons. I was assuming a reference comparison but a value comparison is used. When actually passing an id
to the creation of the mock, it should work.
For convenience a copy of the proposed solution by Telerik.
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;
}
}
Upvotes: 1
Reputation: 14147
You need to use Autofixture for these types of scenarios. https://github.com/AutoFixture/AutoFixture.
Upvotes: 0
Reputation: 78
Use InSequence()
eg :
var firstMock = Mock.Create<MyStruct>();
Mock.Arrange(() => firstMock.ToString()).Returns("Read me!").InSequence();
var secondMock = Mock.Create<MyStruct>();
Mock.Arrange(() => secondMock.ToString()).Returns("Read me too!").InSequence();
Upvotes: 0