英文:
Under what circumstances might DateTime.Today return yesterday's date?
问题
在我们的代码库中,有一个使用属性 [Theory, MemberData(nameof(CancelledDates))]
的 XUnit 理论测试。以下是提供 MemberData 的方法。
public static IEnumerable<object[]> CancelledDates()
{
return new[]
{
new object[] { DateTime.Today.AddDays(5), DateTime.Today.AddDays(10), false, "事故日期不能早于保单起始日期。" },
new object[] { DateTime.Today.AddDays(-10), DateTime.Today.AddDays(-5), false, "事故日期不能晚于保单结束日期。" },
new object[] { DateTime.Today.AddDays(-5), DateTime.Today, true, string.Empty },
new object[] { DateTime.Today, DateTime.Today.AddDays(5), true, string.Empty },
};
}
问题出在第三个条目;当我在 2023/07/13 的 16:00 左右运行测试时,测试失败了,因为提供给测试的日期比预期的早了一天。与预期的 2023-07-08T00:00:00.0000000+02:00
和 2023-07-13T00:00:00.0000000+02:00
不同,提供给测试的日期是 2023-07-07T00:00:00.0000000+02:00
和 2023-07-12T00:00:00.0000000+02:00
。这导致测试失败,因为根据受测试代码,第二个日期不应早于今天。
奇怪的是,这不是每次运行测试都会发生的。似乎只有在 Visual Studio 中运行测试和需要测试通过的 Azure DevOps 构建中才会发生这种情况。我的计算机上的日期和时间是正确的,并且时区设置为 UTC+2。
这种情况已经随机发生了好几个月;我已经受够了,希望能找到解决方案,或者至少理解为什么会发生这种情况。有什么想法吗?
英文:
In our codebase there is an XUnit theory that uses the attribute [Theory, MemberData(nameof(CancelledDates))]
. Here is the method that provides the MemberData.
public static IEnumerable<object[]> CancelledDates()
{
return new[]
{
new object[] { DateTime.Today.AddDays(5), DateTime.Today.AddDays(10), false, "Incident date cannot be before the Cover Start date of the Policy." },
new object[] { DateTime.Today.AddDays(-10), DateTime.Today.AddDays(-5), false, "Incident date cannot be after the Policy Cover End date." },
new object[] { DateTime.Today.AddDays(-5), DateTime.Today, true, string.Empty },
new object[] { DateTime.Today, DateTime.Today.AddDays(5), true, string.Empty },
};
}
The problem is the third entry; when I ran tests around 16:00 on 2023/07/13 the test failed because the dates were one day earlier than they should have been. Rather than 2023-07-08T00:00:00.0000000+02:00
and 2023-07-13T00:00:00.0000000+02:00
as expected, the dates provided to the test were 2023-07-07T00:00:00.0000000+02:00
and 2023-07-12T00:00:00.0000000+02:00
. This results in the test failing as the second date is expected not to be earlier than today in the code under test.
The strange thing is that this does not happen every time the test is run. It seems to happen only when running tests in Visual Studio and Azure DevOps builds that require tests to pass never seem to fail on this test. The date and time on my machine are correct and the time zone is set to UTC+2.
This has been happening to me randomly for several months; I'm tired of it and would love to find a solution or at least understand why it happens. Any ideas?
答案1
得分: 0
我认为您的问题是,xUnit在VS中在构建时序列化测试,以生成测试运行器的名称:https://github.com/xunit/xunit/issues/1473#issuecomment-333226539
当您在没有进行清理构建的情况下稍后运行测试(也许是第二天),动态数据就会过时。这在DevOps中并不是问题,因为它在一次操作中构建、序列化和运行测试。
我曾经尝试寻找解决方法,并回顾了我之前遇到过的一些更改,但找不到令人满意的解决方案。我依稀记得有一种方法可以强制xUnit或VS测试运行器将整个Theory显示为一个带有(静态)方法名称的测试,但这并不是一个很好的“修复”。
在您的情况下,最好的解决方案可能是将偏移量传递给测试,而不是传递日期本身,这意味着您会为测试提供静态数据,而VS/xUnit可以生成测试名称,而不会锁定过时的数据:
public static IEnumerable<object[]> CancelledDates()
{
return new[]
{
new object[] { 5, 10, false, "Incident date cannot be before the Cover Start date of the Policy." },
new object[] { -10, -5, false, "Incident date cannot be after the Policy Cover End date." },
new object[] { -5, 0, true, string.Empty },
new object[] { 0, 5, true, string.Empty },
};
}
然后,在测试方法内部,您可以使用 DateTime.Today.AddDays(offset)
简单地解析偏移量。
作为一般规则,不要通过 MemberData
传递任何您不能通过 InlineData
传递的数据,即非常量数据。
希望这可以帮助您
英文:
I believe your issue is that xUnit serialises tests at build time in VS in order to generate names for the test runner:
https://github.com/xunit/xunit/issues/1473#issuecomment-333226539
When you later run the tests without a clean build (perhaps the next day), the dynamic data is stale.
This is not an issue in DevOps as it builds, serialises and runs the tests in one go.
I had a look to find a fix, and looked back at some of my own changes as I have encountered this before, but cannot find anything satisfactory. I have a vague memory there is a way to force xUnit or the VS test runner to display the entire Theory as one test with the (static) method name, but this isn't much of a "fix".
The best solution in your instance is probably to pass the offsets into the test rather than the dates themselves, meaning you'd provide static data to the tests and VS/xUnit can generate test names without locking in stale data:
public static IEnumerable<object[]> CancelledDates()
{
return new[]
{
new object[] { 5, 10, false, "Incident date cannot be before the Cover Start date of the Policy." },
new object[] { -10, -5, false, "Incident date cannot be after the Policy Cover End date." },
new object[] { -5, 0, true, string.Empty },
new object[] { 0, 5, true, string.Empty },
};
}
Then, inside your test method you can simply parse the offsets with DateTime.Today.AddDays(offset)
.
As a general rule of thumb, don't pass any data via MemberData
that you wouldn't be able to pass via InlineData
- i.e. non-constant data.
Hope this helps
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论