今天,进行单元测试时,当执行到第二个测试类时——之前从来没有错误的测试居然报了:基础连接已经关闭 接收时发生错误。想想今天唯一改动的是在测试代码中加了下列两个执行体:
[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); } }