It's very easy to write unit tests for legacy code using unconstrained frameworks, such as TypeMock Isolator.
But what about writing unit tests for newly written code? Is it a good practice to use an unconstrained framework in such scenario? Or would a constrained framework (such as NSubstitute) enforce better software design?
Update: An unconstrained framework is a framework that can fake almost anything, including static classes, static constructors, and static methods. They make it possible for example to fake the result of DateTime.Now.
1 Answer 1
Whether or not you need to use a unit testing framework is up to you. Any dependency will need to be faked so that logic can be tested in isolation. With legacy code where the dependencies are not visible a mocking or faking framework can help expose those dependencies for you and replace them so you can test that code easily without major refactoring.
In new/greenfield development, one can certainly not use a mocking framework if all the dependencies are exposed. This means that the developer is responsible for writing all the mocks instead of the framework generating them for you. You may decide its easier to let the framework inline those dependencies instead of the team writing the mocks/fakes manually.
If you don't want to use a framework, as an example consider calculating an age. This may also answer @Greg B question as well, why you would want to mock DateTime.Now
. It needs the current time to calculate the age which will be difficult to produce consistent tests results since the current time changes.
Interface
public interface IClock
{
DateTime Now { get; }
}
Real Implementation
public class SystemClock : IClock
{
public DateTime Now { get { return DateTime.Now; } }
}
Class
public class DateLogic
{
private readonly IClock _clock;
public DateLogic(IClock clock)
{
_clock = clock;
}
public int CalculateAge(DateTime dateOfBirth)
{
DateTime now = _clock.Now;
int age = now.Year - dateOfBirth.Year;
if (now < dateOfBirth.AddYears(age)) age--;
return age;
}
}
Mock/Fake Clock
public class MockClock200011 : IClock
{
public DateTime Now {get {return new DateTime(2000,1,1); } }
}
Test
[TestMethod]
public void TestCalculateAge()
{
var expected = 30;
DateTime birthday = new DateTime(1969, 9, 11);
IClock clock = new MockClock200011();
var dateLogic = new DateLogic(clock);
var actual = dateLogic.CalculateAge(birthday);
Assert.AreEqual(expected, actual);
}
So, in this case we wrote our own mock instead of having the framework do it and have put our age calculation in isolation. Doesn't matter what year/time, the test will produce the same results. I don't see any cons of using a framework besides cost and a dependency on that software. As one can see, you can get by without it provided the dependencies are exposed for mock/fake implementations.
-
I'm a little unclear on what this answer is trying to say. In particular, I don't know when you're referring to an unconstrained framework vs. a standard mocking library, which I think is the crux of the questionBen Aaronson– Ben Aaronson2015年05月08日 15:59:19 +00:00Commented May 8, 2015 at 15:59
-
1In my opinion, there is no difference (contrained/unconstrained) other than the amount of mocking features (what it can mock). If you have static methods and you need to mock them, then you will need a unconstrained framework to do that.Jon Raynor– Jon Raynor2015年05月08日 16:27:21 +00:00Commented May 8, 2015 at 16:27
-
2Or inject those static dependencies and mock them yourself. If you need an unconstrained framework to do unit testing, then yes, your code needs refactoring to eliminate those statics with side effects.Jon Raynor– Jon Raynor2015年05月08日 16:34:13 +00:00Commented May 8, 2015 at 16:34
-
What about unit testing OO code, where you have a class which instantiates a stateful object of some other class? Many well-designed classes don't implement a separate interface, nor are they designed for extension by subclassing (therefore, they won't have
virtual
methods). To unit test the first class in isolation from the second, you either need an unconstrained mocking library, or you need to compromise the design to work around the limitations in a constrained mocking library.Rogério– Rogério2015年05月11日 17:04:05 +00:00Commented May 11, 2015 at 17:04 -
@Regerio - I concur with your comment(s).Jon Raynor– Jon Raynor2015年05月13日 17:39:50 +00:00Commented May 13, 2015 at 17:39
DateTime.Now
?