今天,进行单元测试时,当执行到第二个测试类时——之前从来没有错误的测试居然报了:基础连接已经关闭 接收时发生错误。想想今天唯一改动的是在测试代码中加了下列两个执行体:
[TestFixtureSetUp]
public void Set()
{
CommonFuns.SetTime();
}
[TestFixtureTearDown]
public void Restore()
{
CommonFuns.RestoreTime();
}
其中,Set用来设置系统当前时间为制定值,Restore用来恢复系统时间。
然后,手动一个一个测试类执行过来,都是好的。为了确认问题的确是上述代码执行造成的,把上面代码注销后再次整体执行,没有报错;再次加上代码,整体执行,报错,重复上面两个,都是同一现象。确定问题原因是这段系统时间调整造成的。
想到手动执行就没有问题,猜测可能是因为系统执行过程中,从一个上一个类的恢复时间到下一个类的调整时间,然后又马上调用实际的测试代码,造成服务端(开发环境测试代码与服务端在同一电脑上)代码执行时系统时间错乱,从而造成超时等时间原因,最后关闭连接。因此,决定模拟手动操作,在调整和恢复时间后,加上1秒的延时再执行具体的测试方法。经过测试,问题解决。
系统时间调整代码如下:
using System.Runtime.InteropServices;
namespace VME.UnitTest.Service
{
public class SystemTimer
{
//imports SetLocalTime function from kernel32.dll
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int SetLocalTime(ref SystemTime lpSystemTime);
//struct for date/time apis
public struct SystemTime
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
}
}
public static void SetTime()
{
SetTime(0);
}
public static void RestoreTime()
{
RestoreTime(0);
}
/// <summary>
/// 将时间从15点开始向后拨5小时
/// </summary>
public static void SetTime(int day)
{
_diffHours = 0;
if (DateTime.Now.Hour > 15)
{
_diffHours = 5;
// And then set up a structure with the required properties and call the api from code:
SystemTimer.SystemTime systNew = new SystemTimer.SystemTime();
// 设置属性
systNew.wDay = Convert.ToInt16(DateTime.Now.AddDays(day).Day);
systNew.wMonth = Convert.ToInt16(DateTime.Now.Month);
systNew.wYear = Convert.ToInt16(DateTime.Now.Year);
systNew.wHour = Convert.ToInt16(DateTime.Now.Hour - _diffHours);
systNew.wMinute = Convert.ToInt16(DateTime.Now.Minute);
systNew.wSecond = Convert.ToInt16(DateTime.Now.Second);
// 调用API,更新系统时间
SystemTimer.SetLocalTime(ref systNew);
Thread.Sleep(1000);
}
}
/// <summary>
/// 将时间拨回
/// </summary>
public static void RestoreTime(int day)
{
if (_diffHours > 0)
{
// And then set up a structure with the required properties and call the api from code:
SystemTimer.SystemTime systNew = new SystemTimer.SystemTime();
// 设置属性
systNew.wDay = Convert.ToInt16(DateTime.Now.AddDays(day).Day);
systNew.wMonth = Convert.ToInt16(DateTime.Now.Month);
systNew.wYear = Convert.ToInt16(DateTime.Now.Year);
systNew.wHour = Convert.ToInt16(DateTime.Now.Hour + _diffHours);
systNew.wMinute = Convert.ToInt16(DateTime.Now.Minute);
systNew.wSecond = Convert.ToInt16(DateTime.Now.Second);
// 调用API,更新系统时间
SystemTimer.SetLocalTime(ref systNew);
_diffHours = 0;
Thread.Sleep(1000);
}
}