Reputation: 5047
Starting with unit testing, I wonder how to test our old code, that looks something like that:
public Player DetermineWinner(Player a, Player b)
{
if(a.Age>b.Age)
....
///few more conditions checking properties of both players
}
class Player
{
public Player (DBConnection c, world w, DateTime logTime)
{} //not easy to mock...
}
How to mock that? I understand that if the Player implemented an interface, I could simply create a mock and pass it in the unit test with desired values, but that is not the case here. The Player class is instantiated using various parameters so I cannot simply create an instance during the unit test and pass it - it depends on various external objects. I would need to mock the Player object and set its properties at the same time so that the tests are deterministic. What is the best approach to start with?
Should I next time use interfaces to decouple that?
Upvotes: 0
Views: 666
Reputation: 745
you can unit-test your code without changing it, by using a framework like Typemock that let you mock concrete dependency with no need for added interfaces and when you choose a class to be mock (in this case "Player", typemock will also automatically mock all the dependencies in it).
On your given example:
public class UnitTest1
{
[TestMethod]
public void TestDetermineWinner_B_IsTheWinner()
{
var P1 = Isolate.Fake.Instance<Player>();
var P2 = Isolate.Fake.Instance<Player>();
Isolate.WhenCalled(() => P1.Age).WillReturn(0);
Isolate.WhenCalled(() => P2.Age).WillReturn(1);
var result = new ClassUnderTest().DetermineWinner(P1, P2);
Assert.AreEqual(P2, result);
}
}
public class ClassUnderTest
{
public Player DetermineWinner(Player a, Player b)
{
if (a.Age > b.Age) { return a; }
return b;
///few more conditions checking properties of both players
}
}
public class Player
{
public Player(DbConnection c, world w, DateTime logTime)
{ } //not easy to mock...
public int Age { get; internal set; }
}
Upvotes: 1
Reputation: 140457
I think you do not understand what mocking really means.
A mocked object has nothing to do with the "real" implementation of that class. It just "looks" like an object of that class.
But you (resp. the mocking framework) are in control regarding the behavior of that object. Well, unless the field is private (see here on that). So: when your Player fields are not private, you don't have a problem.
Without a mocking framework - you really can't do much. If at all, you could be mocking all the objects that are required as parameter to the constructor of your class under test.
In other words: in the end, you need some object "x" of class "X"; and when using the "real" class "X" gives you so much trouble, then you have to replace it with something that looks like "X".
Worst case, you could have two different versions of the X class; but that would make things pretty complicated.
Upvotes: 0