When code processes dates based on the current date, testing should cover edge cases such as leap years as well as the more frequent month and year boundaries.
In our code we always get the current date deep down in our classes using DateTime.Now (.NET, in our case).
How can you unit test such code?
Is this where Dependency Injection becomes very useful?
Edit
This is a slight aside, but apparently the next version of Typemock will allow faking of DateTime.Now
https://blog.typemock.com/2009/05/mockingfaking-datetimenow-in-unit-tests.html
In our code we always pull out the current date using DateTime.Now (.NET, in our case). How can you unit test such code?
This is a dependency, and a non-deterministic dependency at that. You need to divide the responsibility of the code up a little more.
Before:
There is some code that uses the current datetime to do X.
After:
There should be some code that is responsible for getting the current datetime.
There should be some code that uses a datetime to do X.
These two sets of code should not be dependent on each other.
This pattern of seperating dependencies works for other cases as well (database, filesystem, etc).
Using DI for injecting "Current Date & Time" is surely an overkill. I'd rather refactor the code to operate on arbitrary date. That is, I'd change function calculateRevenue() to function calculateRevenueOn(datetime date). This is much easier to test and use in case you need calculation for some dates other than current.
I've used the very pragmatic approach discussed by Oren Eini (aka Ayende Rahien) in his blogspots Dealing with time in tests.
There is a static class like this:
public static class SystemTime
{
public static Func<DateTime> Now = () => DateTime.Now;
}
Your code becomes:
Entity.LastChange = SystemTime.Now();
And your test would become:
SystemTime.Now = () => new DateTime(2000,1,1);
repository.ResetFailures(failedMsgs);
SystemTime.Now = () => new DateTime(2000,1,2);
var msgs = repository.GetAllReadyMessages();
Assert.AreEqual(2, msgs.Length);
Always put the core date processing logic (which is, in my experience, usually easy to isolate for this purpose) into separate methods that take the date as a parameter.
Then, in your production code you can call those and give them the current date as parameter, and still test edge cases to your heart's content in unit tests.
BTW, I've found it quite crucial to test date logic very intensively for edge cases. It eliminates (possibly catastrophic, ref. Zune) bugs that you'd never have found otherwise. Apart from the ones you mentioned, daylight savings time switches can also be problematic.
You already gave the answer. You can write a small wrapper class around datetime functions that you can then inject in the classes that need to get the current date. Replacing DateTime.Now with a call to your wrapper object.
In your tests you can then inject a stub or mock object that gives you the date you need.
Another solution might be, depending on how your code works, just pass the date as a parameter instead of burying calls to datetime.Now. This makes your code a bit more reusable because it can work on more than the current date
public interface ITimeProvider {
DateTime Now { get; }
}
public class SystemTimeProvider : ITimeProvider {
public virtual DateTime Now { get { return DateTime.Now; } }
}
public class MockTimeProvider : ITimeProvider {
public virtual DateTime Now { get; set; }
}
public class ServiceThatDependsOnTime {
protected virtual ITimeProvider { get; set; }
public ServiceThatDependsOnTime(ITimeProvider timeProvider) {
TimeProvider = timeProvider;
}
public virtual void DoSomeTimeDependentOperation() {
var now = TimeProvider.Now;
//use 'now' in some complex processing.
}
}
[Test]
public virtual void TestTheService() {
var time = new MockTimeProvider();
time.Now = DateTime.Now.AddDays(-500);
var service = new ServiceThatDependsOnTime(time);
service.DoSomeTimeDependentOperation();
//check that the service did it right.
}
you could make a mockobject that simulates the DateTime.Now
here is article with an example where DateTime.Now is being mocked: Link
Dependency injection can be a solution for this, yes.
What you will do is create, for example, an IDateTimeProvider interface with a method: GetDate(). In your production-code class you will implement return DateTime.Now.
When unit testing, as Natrium suggested, you can then replace this with a mock object, one that returns a certain date to test on.
Why not use Fakes? With Visual Studio is as easy as possible. Just add a fake assembly to System, add the ShimsContext to your test,
using (ShimsContext.Create())
{
And set the DateTime.Now to return a specific value:
System.Fakes.ShimDateTime.NowGet = () => new DateTime(2000, 1, 1);
This approach makes sure every call to DateTime.Now is redirected to your code, so you don't have to inject anything to get the current time (which should be really straightfoward) nor you need a global, writable, variable.
Related
I want to write a unit test that check a stream has been copied on the disk :
The problem is CopyTo method is not virtual so I can't use
inputMemoryStreamMock.Verify(c => c.CopyTo(outputMemoryStreamMock.Object));
and I don't know how to mock a stream :-/
here is my test method :
[TestMethod]
public void Save_Stream_On_DestinationPath()
{
// Arrange
string fileName = "filename.pdf";
DateTime date = new DateTime(2013, 9, 27);
var serverConfigMock = new Mock<IServerConfigurationManager>();
serverConfigMock.Setup(config => config.ReportingBasePath).Returns(#"c:\reportsFolder");
var factoryReportFileResultMock = new Mock<IReportFileResultFactory>();
var timeManagementMock = new Mock<ITimeManagement>();
timeManagementMock.Setup(c => c.GetServerDate()).Returns(date);
var fileSystemMock = new Mock<IFileSystem>();
var fileInfoFactory = new Mock<IFileInfoFactory>();
var directoryInfoBaseMock = new Mock<DirectoryInfoBase>();
var inputMemoryStreamMock = new Mock<Stream>();
var outputMemoryStreamMock = new Mock<Stream>();
var reportFileHelper = new ReportFileHelper(serverConfigMock.Object, factoryReportFileResultMock.Object, fileSystemMock.Object);
inputMemoryStreamMock.Setup(c => c.CanRead).Returns(true);
outputMemoryStreamMock.Setup(c => c.CanWrite).Returns(true);
outputMemoryStreamMock.Setup(c => c.CanWrite).Returns(true);
fileSystemMock.Setup(c => c.FileInfo).Returns(fileInfoFactory.Object);
fileSystemMock.Setup(c => c.File.Create(It.IsAny<string>())).Returns(outputMemoryStreamMock.Object);
fileSystemMock.Setup(c => c.Directory.CreateDirectory(It.IsAny<string>())).Returns(directoryInfoBaseMock.Object);
// Act
reportFileHelper.Save(inputMemoryStreamMock.Object, fileName, timeManagementMock.Object);
// Assert
inputMemoryStreamMock.Verify(c => c.CopyTo(outputMemoryStreamMock.Object));
}
And here is the method to test :
public void Save(Stream portfolioReportFileInfoBase, string destinationName, ITimeManagement timeManagement)
{
string destinationPath = GetDestinationPath(timeManagement);
string destinationFileUri = Path.Combine(destinationPath, destinationName);
FileSystem.Directory.CreateDirectory(destinationPath);
using (var fileStream = FileSystem.File.Create(destinationFileUri))
{
portfolioReportFileInfoBase.CopyTo(fileStream);
}
}
Thank you
My take on a couple of things :
Readability
I'm not sure your test reads very nicely. Why do you declare a fileName variable as though it were important while you don't even assert on it ? Same goes for date. This clutters your test with unneeded detail. Inline values or Anonymous Variables allow for a better signal/noise ratio.
Then why do you set up CreateDirectory() to return something ? You never use that return value, do you ? I suggest you get rid of that and the directoryInfoBaseMock variable. Same with FileInfo and fileInfoFactory. Your test needs to contain the bare minimum to set up the objects you want to verify, and nothing more. If you need to build a deep, complex graph of objects just to test one simple thing, there's generally a problem somewhere.
Design
The second thing that raises an alarm is that Save() mixes multiple language levels. When you read it, it seems to be at the same time about :
Portfolios and reports
Time management
A lot of lower level filesystem stuff
This is often a sign that an object tries to handle too much, violating the Single Responsibility Principle.
What I would do is distribute these responsibilities across separate objects.
Why does Save() need to know about time management ? Sure, we use time management to compute the destination path, but wouldn't it be better aligned with the language level and responsibility level of a Save() method if we directly passed it the destination path instead ?
Why does Save() need to know about portfolios and reports ? Well, there's basically no reason. You could just rename portfolioReportFileInfoBase to... stream.
Save() and GetPath() could then be moved to a separate lower-level filesystem wrapper class (IFileSystem is a perfect candidate), removing the tight coupling between ReportFileHelper and the filesystem.
Don't try to test that your report is written to the disk using mocks. Do it with an integration test. Don't mock types you don't own. Use mocks only to test how your own classes talk to each other. Wrap external libraries/platforms into wrapper objects, and write integration tests at the boundaries of your application to verify that your wrappers play well with those external libraries/platforms.
You'll have to use an isolation framework like TypeMock Isolator or Microsoft Fakes to test this case if you're not willing to change the code of the Save method, since CopyTo can't be mocked by Moq.
You already encapsulated access to the filesystem behind IFileSystem; why not just add a method like CopyStreamToPath?
public void Save(Stream portfolioReportFileInfoBase, string destinationName, ITimeManagement timeManagement)
{
string destinationPath = GetDestinationPath(timeManagement);
string destinationFileUri = Path.Combine(destinationPath, destinationName);
FileSystem.Directory.CreateDirectory(destinationPath);
FileSystem.CopyStreamToPath(portfolioReportFileInfoBase, destinationFileUri);
}
and the test:
fileSystemMock.Verify(c => c.CopyStreamToPath(inputMemoryStreamMock.object, It.IsAny<string>()));
I have an ASP.NET page that is the base to many more derived pages and it contains the following protected method
protected Change SetupApproval(string changeDescription)
{
Change change = Change.GetInstance();
change.Description = changeDescription;
change.DateOfChange = DateTime.Now;
change.MadeBy = Common.ActiveDirectory.GetUsersFullName(AccessCheck.CurrentUser());
change.Page = PageName;
return change;
}
I want to write the following Unit test
[TestMethod]
public void SetupApproval_SubmitChange_ValidateDescription()
{
var page = new DerivedFromBaseClass();
var messageToTest = "This is a test description";
var change = (page as InternalAppsPage).SetupApproval(messageToTest);
Assert.IsTrue(messageToTest == change.Description);
}
I'm sure there's a lot wrong with this code (so feel free to suggest corrections), but my main goal is to start implementing some tests for this entire project. I decided to start small - one method at a time. I first tried creating a new Test Project, but then I can't access the SetupApproval method because it is protected. My next attempt was to put the TestMethod inside of the base page, but then there's no way to Run Tests.
Lastly, I'm using Visual Studio 2008's default test framework.
Two options:
Assuming DerivedFromBaseClass is a class which solely exists for testing, just give it a new public (or internal) method which just calls SetupApproval and returns the return value.
Make the method protected internal instead, and make sure you have InternalsVisibleTo set up for your test assembly so it has access to internal methods. Document that this is for the sake of testing.
The first option is cleaner, the second is simpler, particularly if you have a lot of protected methods and the base class is non-abstract.
I am testing a method on my class that does some date checking. The problem is that the method depends on today's date (which changes every day), which makes this difficult to test. How can I mock today's date so that my tests will still pass tomorrow?
I know nothing about PHP, but in both Java and C# I would pass in a "clock" of some description - not today's date itself, but an object which you can ask for the current date/time. Then in unit tests you can pass in an object which can give any date you want - including one that's hard-coded into the tests.
Does that work in PHP too?
If your interest is to not pass in the date to preserve the external interface, then a good way to do this is to use a "seam" to provide the date:
class MyClass {
public function toBeTested() {
$theDate = $this->getDate();
...
}
protected function getDate() {
return date();
}
}
In general use, this class just works normally.
Then, in your unit testing, instead of testing MyClass, you extend MyClass with an inner class that overrides the getDate() function:
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase {
static $testDate;
public function testToBeTested() {
//set the date to be used
MyTest::testDate = '1/2/2000';
$classUnderTest = new MyClassWithDate();
$this->assertEquals('expected', $classUnderTest->toBeTested());
}
}
//just pass back the expected date
class MyClassWithDate extends MyClass {
protected function getDate() {
return MyTest::testDate;
}
}
In this code, you test against your extension of the real class, but your extension overrides the seam function (getDate()), and returns back the date that you want to use for this particular test.
Again, sorry if there are some egregious syntax errors, this was written freehand.
While Jon's answer is the "right way," another option is to use the runkit extension to temporarily replace the date() and/or time() functions with ones that return a fixed value for the test.
Make sure to set runkit.internal_override in php.ini so you can rename built-in functions.
Rename the original function using runkit_function_rename.
Rename your mock function with the original's name.
Test.
Rename your mock back.
Rename the original back.
Here's some completely untested code to help with this:
function mock_function($original, $mock) {
runkit_function_rename($original, $original . '_original');
runkit_function_rename($mock, $original);
}
function unmock_function($original, $mock) {
runkit_function_rename($original, $mock);
runkit_function_rename($original . '_original', $original);
}
You should use these from within the setUp() and tearDown() methods to make sure you don't interfere with other tests that follow.
I know you don't want to pass it in as an argument. But maybe you can rethink this ...
When being passed as a parameter from the outside, the date is not an insignificant technical detail, but a significant functional rule. Don't you need any of the following?
Although the current date can be the regular use case, the rule might be applicable to another date. Then your code would be more general, and work in a later use case with no modification. That happens to me regularly ...
Several codes could use the current date in an algorithm. Because the computer speed is not infinite, several would get a different instant ... Is that logical functionally? Or would using the same instant (for example, the instant your user pressed the "Fire" button) be more accurate? Think how you might request these times in your database later on, if they are all different in your database, even if they represent the same instant for your user!
I couldn't rename twice as David says, so I got it like:
function mockDate()
{
runkit_function_rename('date', 'test_date_override');
runkit_function_add('date','$format=NULL,$timestamp=NULL,$locale=NULL', 'return DATEMOCK;');
}
function unmockDate()
{
runkit_function_remove('date');
runkit_function_rename('test_date_override', 'date');
}
A second MSpec question from me in a day, this is a new record. I'm trying to get smart on MSpec very quickly and I've run into some old problems I've always had with MSpec.
Scenario: I have a repository that contains a bunch of cartoons. Right now I only need to filter this set on a single Name parameter, which is a string. As I'm told I'll need to filter this on more properties later on, I decide to create a class which takes in my ICartoonRepository via IoC, and contains a simple method that's called GetByName(string name).
You might argue this is overkill, but I'm trying to teach myself how to use MSpec and work in a more TDD manner.
So I create the following:
[Subject(typeof(CartoonViewModelBuilder))]
public class when_cartoon_repository_is_asked_to_get_by_id : specification_for_cartoon_viewmodel_builder
{
static string name;
static Cartoon the_cartoon;
static Cartoon result;
Establish context = () =>
{
name = "Taz";
the_cartoon = new Cartoon();
the_cartoon_repository.Stub(r => r.GetAll().Where(x=>x.Name == name).FirstOrDefault()).Return(the_cartoon);
};
Because of = () => result = subject.GetByName(name);
It should_return_cartoon = () => result.ShouldBeTheSameAs(the_cartoon);
}
This fails on the stub as the repository is empty. I have a couple other tests that pass fine (simply testing the GetAll(), etc). Do I need to add things to the repository to test it? This is where I'm stumped, please be gentle.
Also, if I'm writing the linq statement in the stub, it seems like I'm doing it twice, in the actual implementation and in the test. Is this the point? It doesn't feel right. Is there a better way I can write this test?
For clarity sake, here is the actual implementation (I'm omitting the interface and the class, which just has one property:
public class CartoonViewModelBuilder: ICartoonViewModelBuilder
{
readonly ICartoonRepository _cartoonRepository;
public CartoonQueryObject(ICartoonRepository cartoonRepository)
{
_cartoonRepository = cartoonRepository;
}
public IList<Cartoon> GetAllCartoons()
{
return _cartoonRepository.GetAll();
}
public Cartoon GetByName(string name)
{
return _cartoonRepository.GetAll().Where(x => x.Name == name).FirstOrDefault();
}
}
Edit 1: Based on the lack of responses, I should say that if I were using something like NUnit, I would be creating a method on the testing class that was like, "LoadDummyData" and threw data into the repository, then I'd do complex filtering or view model building and sort of manually checked what happened. This made large refactoring a chore. It seems like specs allows you to avoid that?
Edit 2: Here's my corrected test which now passes. Let me know if I'm doing it right, I think I am. Thanks again for the hand holding!
static string name;
static Cartoon the_cartoon;
static Cartoon result;
static IQueryable<Cartoon> the_cartoons;
Establish context = () =>
{
name = "Taz";
the_cartoon = new Cartoon {Name = name};
the_cartoons = new List<Cartoon> {the_cartoon, new Cartoon(), new Cartoon() }.AsQueryable();
the_cartoon_repository.Stub(r => r.GetAll()).Return(the_cartoons.ToList());
};
Because of = () => result = subject.GetByName(name);
It should_return_cartoon = () => result.ShouldBeTheSameAs(the_cartoon);
Edit 3: Gave you both points, but I can only award one best answer unfortunately.
The actual reason of this test failing is the way you're mocking your repository. I would be very surprised if method chains like r.GetAll().Where(x=>x.Name == name).FirstOrDefault() could be mocked so easily, as it uses LINQ extension methods and lambda clauses. The framework should really throw NotSupported exception or something to let you know that you can't mock LINQ queries as a whole.
To mock LINQ query result, you should provide properly prepared underlying data collection, which is the starting point of LINQ query. In your example you should mock just r.GetAll() to return a collection containing your element with proper name. The actual query will run on your "mocked" data and retrieve the object you expect.
This removes the need to duplicate your LINQ query in code and in test, what is strange, as you noted.
EDIT: Code in your edit is like I've suggested, technically OK.
Anyway, by now it's a bit overkill, as you've said. Your class under test doesn't do anything beside the call to the mocked repository, so the value of that test is rather small. But it may be a good start if you're going to have some more logic in GetByName method.
If you want to test your repository implementation, don't stub it! MSpec or not, I would add a list of known items to the repository and then issue the query with GetByName. Then assert that just the item you expect was returned. I would also use ShouldEqual as the repository might work with the items you add and return a different instance, though considered equal (aggregate IDs are equal).
I was wondering whether the object to test should be a field and thus set up during a SetUp method (ie. JUnit, nUnit, MS Test, …).
Consider the following examples (this is C♯ with MsTest, but the idea should be similar for any other language and testing framework):
public class SomeStuff
{
public string Value { get; private set; }
public SomeStuff(string value)
{
this.Value = value;
}
}
[TestClass]
public class SomeStuffTestWithSetUp
{
private string value;
private SomeStuff someStuff;
[TestInitialize]
public void MyTestInitialize()
{
this.value = Guid.NewGuid().ToString();
this.someStuff = new SomeStuff(this.value);
}
[TestCleanup]
public void MyTestCleanup()
{
this.someStuff = null;
this.value = string.Empty;
}
[TestMethod]
public void TestGetValue()
{
Assert.AreEqual(this.value, this.someStuff.Value);
}
}
[TestClass]
public class SomeStuffTestWithoutSetup
{
[TestMethod]
public void TestGetValue()
{
string value = Guid.NewGuid().ToString();
SomeStuff someStuff = new SomeStuff(value);
Assert.AreEqual(value, someStuff.Value);
}
}
Of course, with just one test method, the first example is much too long, but with more test methods, this could be safe quite some redundant code.
What are the pros and cons of each approach? Are there any “Best Practices”?
It's a slippery slope once you start initializing fields & generally setting up the context of your test within the test method itself. This leads to large test methods and really really unmanageable fixtures that don't explain themselves very well.
Instead, you should look at the BDD style naming & test organization. Make one fixture per context, rather than one fixture per system-under-test. Then your [setup] truly does setup the context, and your tests can be simple one-liner asserts.
It's much easier to read when you see a test output that does this:
OrderFulfillmentServiceTests.cs
with_an_order_from_a_new_customer
it should check their credit from the credit service
it should give no discount
with valid credit check
it should decrement inventory
it should ship the goods
with a customer in texas or california
it should add appropriate sales tax
with an order from a gold customer
it should NOT check credit
it should get expedited shipping added for free
Our tests are now really good documentation for our system. Each "with_an..." is a test fixture, and the items below it are tests. Within those, you setup the context (the state of the world as the class name describes) and then the test does the simple assert that verifies what the method name says it does.
The second approach is much more readable, and much easier to visually trace.
However, the first approach means less repetition.
What I've found is that I tend to use the SetUp to create objects (especially for things with a number of dependencies), and then set the values used in the test itself. From experience, this provides about the right amount of code-reuse versus readability/traceability.
From talking with Kent Beck about the design of jUnit I know that Test Classes were a way to share setup between Tests, so using the common initialization was the intent. However, along with that, that means splitting tests that require different setup into separate test classes that have revealing names.
Personally, I use Setup and Teardown methods for two distinct reasons, although I assume that others will have different reasons.
Use Setup and Teardown methods when there is common initiation logic that is used by all tests and a single instance of the object(s) created in the Setup are designed to be reused.
Use Setup and Teardown methods when the time it takes for creating and destroying any object(s) created takes enough time to slow down the unit testing process when repeated in each TestMethod.
To give you an idea of how often I run accross these scenarios, in a project that I am working on now, only two of my test classes (out of about eighty) have an explicit need for Setup and Teardown methods, both times it was to satisfy my second reason due to the 10 second max I have enabled for each test execution.
I also prefer the readability of having the object(s) created and destroyed within the TestMethod, although it is not a breaking or selling point for me.
The approach I take is somewhere in the middle - I use TearDown and SetUp to create a test "sandbox" directory (and delete it when done), as well as to initialize some test member variables with some default values that will be used to test the classes. I then set up some "helper methods" - One is generally called InstantiateClass() I use that to call with the default parameters (if any) which I can override as necessary in each explicit test.
[Test]
public void TestSomething()
{
_myVar = "value";
InstantiateClass();
RunTheClass();
Assert.IsTrue(this, that);
}
In practice, I find set up methods make it hard to reason about a test that is failing and have to scroll to somewhere near the top of the file (which can be very large) to figure out what collaborator has broken (not easy with mocking) and there is no clickable reference to navigate in your IDE. In short, you lose spatial locality.
Static helper methods reveal the collaborators more explicitly, and you avoid fields which unnecessarily widen the scope of variables.