Osy#betaRun it on Osyrin: osyrin.com

Reference / Testing

app.TestClock — pin every test's clock

app.TestClock = new DateTime(year, month, day[, hour, minute[, second]]);

One line in any `.test.osy` file opts the whole project into a pinned test clock: every test and every fixture then starts at that instant instead of the wall clock, so nothing a test asserts depends on the day or hour the suite runs. `TestClock.Set` and `TestClock.Advance` still move it from there.

preview1 example compiled by CItestingtime

Summary#

Without it, a test reads the real clock (or, forked from a fixture, the moment its fixture was seeded — see TestClock.Advance and TestClock.Set). That is right for most suites, and it is why pinning is opt-in: turning it on changes what every existing test reads as "now". A project whose tests reason about dates — a booking for tomorrow, a monthly report, a reminder at nine — opts in once:

app.TestClock = new DateTime(2030, 1, 15, 9, 30, 0);   // in any .test.osy — read as UTC

Then DateTime.UtcNow in every test body, in every fixture, in a query's Where(…), on the page a test opens and in the server call a click makes all read 15 January 2030, 09:30 — on every machine, on every day.

Signature#

app.TestClock = new DateTime(<year>, <month>, <day>);
app.TestClock = new DateTime(<year>, <month>, <day>, <hour>, <minute>, <second>);

Description#

  • Per project. Write it once, in any one of the files your tests glob collects; it applies to every test file.
  • Pinned, not running. The clock stands at that instant until a test moves it — TestClock.Advance(…) steps it on, TestClock.Set(…) puts it somewhere else. A fixture that moves it hands its tests the instant it left it at.
  • Fixtures start there too. A row a [TestFixture] stamps with DateTime.UtcNow holds the pinned instant, so a test forked from it reads a world built at the same moment it reads as "now".
  • In a .test.osy only. In a model file it would pin nothing, so it is refused there. Outside osy test it does nothing at all: a running app reads the real clock (and osy clock moves a running local app's clock — see Moving the running app's clock).
  • Written out. Year, month and day, then optionally hour, minute and second, as number literals, read as UTC. It is read before anything runs, so it cannot be computed.
app.TestClock = new DateTime(2030, 1, 15, 9, 30, 0);

[Test]
void now_is_the_projects_instant() {
  Assert.Equal(new DateTime(2030, 1, 15, 9, 30, 0), DateTime.UtcNow);
}

[Test]
void a_test_still_moves_it_on() {
  TestClock.Advance(TimeSpan.FromHours(2));
  Assert.Equal(new DateTime(2030, 1, 15, 11, 30, 0), DateTime.UtcNow);
}

See also#

Related

TestClock.Advance and TestClock.Set

In a test, moves the run's clock FORWARD by a duration, then lets the next Workflow.Settle fire every workflow timer…

Fixtures: built once, cloned for every test, and built on each other

A [TestFixture] is built once per run, and every test that names it runs on its own copy of what it left — rows, files…

[Test] / [TestFixture]

A test is an ordinary function marked [Test]. It runs against a throwaway clone of the app, so it may create rows and…