Reputation:
I have the following code here
ITest.cs
public interface ITest
{
int Prop { get; }
int Calc();
}
Test.cs
public class Test : ITest
{
public int Prop { get; private set; }
public int Calc()
{
return Prop * 2;
}
}
And I want to test the Calc()
method. If my understanding is correct You can NOT override the getter property of concrete classes without using the virtual
keyword.
for example
var moq = new Mock<Test>(); // mocked Test class
moq.Setup(x => x.Prop).Returns(2); // throws an error,
// however with "virtual int Prop { get; }" it doesn't throw any exceptions
var moq = new Mock<ITest>(); // mocked ITest interface
moq.Setup(x => x.Prop).Returns(2); // works fine
// but can not really test the Calc() method (it returns 0
// because the proxy doesn't have Test's implementation)
so my question is: how can I test the functionality of Calc()
without making virtual int Prop
btw... this doesn't work either
var moq = new Mock<ITest>();
moq.Setup(x => x.Prop).Returns(2);
var obj = (Test)moq.Object; // can NOT convert ITestProxy to Test
Upvotes: 1
Views: 453
Reputation: 23174
Mocks are to be used as replacement for dependencies around what you are trying to test.
Concerning your test, just test the actual exposed behavior of your class, meaning don't try to use private methods and setters. In any case, mokcing the class to test is not a valid approach.
For instance :
Test
class :[TestClass]
public class TestTests
{
[TestMethod]
public void Calc_WhenPropIsSetTo5_Returns10()
{
/**
* Seems this is what you want to test (see name of methods),
* and I don't think it is a good idea, as your setter is private.
* Since it's not a "public" behavior, you could either
*
* a) have the setter as internal for testing purposes,
*
* b) (my recommendation) go for the two other tests below instead;
* this will actually test the exposed behavior of the class.
*
* c) circumvent the accessibility (by using a library or using
* Reflection directly) to set the value of the prop.
* See your own answer for an example.
*/
}
[TestMethod]
public void Calc_WhenCreatedWith5_Returns10()
{
// Arrange
var testSubject = new Test(5); // if the prop is set by constructor... otherwise arrange in the proper way.
// Act
var actualResult = testSubject.Calc();
// Assert
Assert.AreEqual(expected: 10, actualResult)
}
[TestMethod]
public void Prop_WhenCreatedWith5_IsSetTo5()
{
// Arrange
var testSubject = new Test(5);
// Act
var actualResult = testSubject.Prop;
// Assert
Assert.AreEqual(expected: 5, actualResult)
}
}
ITest.Calc()
,then you should, in your actual code,
1 - depend on the interface ITest
, not on implementation Test
2 - have the dependency injected to the class being tested, so that you can replace the usual implementation Test
by Mock<ITest>.Object()
public class ClassThatUsesTest
{
private readonly ITest _test;
public ClassThatUsesTest(ITest test)
{
_test = test;
}
public int SomeFunction()
{
if (_test.Calc() == 10)
{
return 42;
}
else
{
return 0;
}
}
}
[TestClass]
public class ClassThatUsesTestTests
{
[TestMethod]
public void SomeFunction_WhenTestCalcReturns10_Returns42()
{
// Arrange
var testMock = new Mock<ITest>();
testMock.Setup(x => x.Calc()).Returns(10);
var testSubject = new ClassThatUsesTest(testMock.Object);
var expectedResult = 42;
// Act
var actualResult = testSubject.SomeFunction();
//
Assert.AreEqual(expectedResult, actualResult);
}
}
In the last example, you can see the mocks help us to isolate the test without depending on the actual implementation details of the Test
class. Even if suddenly the actual Test
is broken or change (e.g. you need to pass 6 instead of 5 to get 10), the test method doesn't care.
Upvotes: 0
Reputation:
Found a solution: Pose
It uses ILGenerator and is quite old, BUT it works.
example
var test = new Test(); // default value of 'Prop' is 0
var shim = Shim.Replace(() => test.Prop).With((Test @this) => // idk why he needs @this param
{
return 100; // sets the 'Prop' value to 100
});
var result = 0;
PoseContext.Isolate(() =>
{
result = test.Calc(); // prints 200;
}, shim);
Upvotes: 1
Reputation: 10065
Though this feels not right as it changes method implementation for testing purpose, just for the sake of sharing:
public class Test : ITest
{
private int _prop;
public int Prop
{
get => ((ITest)this).Prop;
private set => _prop = value;
}
public int Calc()
{
return Prop * 2;
}
int ITest.Prop => _prop;
}
In test:
var mock = new Mock<Test>();
mock.As<ITest>()
.Setup(x => x.Prop)
.Returns(3);
// This should return 6
mock.Object.Calc();
Upvotes: -1
Reputation: 21261
If you want to test Calc()
then test Calc()
. You do not need to mock anything
[TestMethod]
public void Test_Calc_DoublesProp()
{
//arrange
var test = new Test(5); //assumes Prop value can be injected in constructor
//act
int result = test.Calc();
//assert
Assert.IsTrue(result == 10); // 5 * 2
}
Upvotes: 1