And*_*eaG 3 tdd nunit ninject moq ninject-2
我正在尝试第一次实现测试驱动的开发.我的项目是dotnet 3.5中的ac#.我已阅读在C#书中专业测试驱动开发,现在我想测试我的项目包含Windows service.I've读到最好的做法是,所有代码必须在test.The以下是我的窗口服务实现方法onStart和onStop
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using log4net;
namespace MyUcmaService
{
public partial class MyUcmaService : ServiceBase
{
private Worker _workerObject;
private static MyUcmaService aMyUcmaService;
private Thread _workerThread;
private static ILog _log = LogManager.GetLogger(typeof(MyUcmaService));
public MyUcmaService()
{
InitializeComponent();
aMyUcmaService = this;
}
protected override void OnStart(string[] args)
{
// TODO: inserire qui il codice necessario per avviare il servizio.
//Debugger.Launch();
AppDomain.CurrentDomain.UnhandledException += AppDomainUnhandledException;
try
{
_workerObject = new Worker();
_workerThread = new Thread(_workerObject.DoWork);
// Start the worker thread.
_workerThread.Start();
}
catch (Exception ex)
{
HandleException(ex);
}
}
protected override void OnStop()
{
// TODO: inserire qui il codice delle procedure di chiusura necessarie per arrestare il servizio.
try
{
_workerObject.RequestStop();
_workerThread.Join();
}
catch (Exception ex)
{
HandleException(ex);
}
}
private static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
HandleException(e.ExceptionObject as Exception);
}
private static void HandleException(Exception ex)
{
if (ex == null)
return;
_log.Error(ex);
if (aMyUcmaService != null)
{
aMyUcmaService.OnStop();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你能告诉我怎样才能在这里实施tdd?谢谢你的回复.
您没有TDD服务,而是您的服务将用于完成其工作的对象.
这有几个优点
底线
因为我刚刚在工作中重构了 4 个现有的 Windows 服务,所以我忍不住提出一个额外的答案!
我所做的就是完全剥离 Windows 服务类,并ServiceBase为 4 种不同的实现创建我自己的类及其 4 个派生类。最根本的原因是,由于测试周期不方便,测试Windows 服务确实很痛苦:
应用更改、构建、卸载 Windows 服务、安装更新的 Windows 服务、测试、调试并重复...
对我来说 TDD-ing Windows 服务的主要目的是:
我从您的代码示例中认识到相同的需求。请允许我展示我自己的简化代码,以描绘您可以采取哪些措施来成功 TDD 您的 Windows 服务。
我将首先展示测试,因为这是有趣的部分。我将在测试下方添加一些已实现类的片段作为参考。
在真正的事情开始之前进行一些设置...
private MockRepository _mocks;
private IAdminLayer _adminLayer;
private IAlertSchedule _alertingServices;
private IAlertManager _alertingManager;
private AutoResetEvent _isExecutedSuccesful;
private AdministratorAlertingService _alertingService;
[SetUp]
public void Setup()
{
_isExecutedSuccesful = new AutoResetEvent(false);
_mocks = new MockRepository();
_adminLayer = _mocks.DynamicMock<IAdminLayer>();
_alertingServices = _mocks.DynamicMock<IAlertSchedule>();
_alertingManager = _mocks.DynamicMock<IAlertManager>();
var settings = _mocks.DynamicMock<ISettingsService>();
using (_mocks.Record())
{
Expect.Call(_adminLayer.LogSource).Return("myLogSource").Repeat.Any();
Expect.Call(_adminLayer.Settings).Return(settings);
Expect.Call(settings.IsInitialised()).Return(true);
Expect.Call(settings.GetAlertSchedule()).Return(_alertingServices);
}
_alertingService = new AdministratorAlertingService(_adminLayer, null);
}
Run Code Online (Sandbox Code Playgroud)
测试OnStart行为:
[Test]
public void AlertingServiceTestOnStart()
{
new Thread(ExecuteOnStart).Start();
Assert.IsTrue(_isExecutedSuccesful.WaitOne());
Assert.IsTrue(_alertingService.ServiceTimer.Enabled);
}
private void ExecuteOnStart()
{
_alertingService.OnStart();
_isExecutedSuccesful.Set();
}
Run Code Online (Sandbox Code Playgroud)
测试OnPause行为:
[Test]
public void AlertingServiceTestOnPause()
{
new Thread(ExecuteOnPause).Start();
Assert.IsTrue(_isExecutedSuccesful.WaitOne());
Assert.IsFalse(_alertingService.ServiceTimer.Enabled);
}
private void ExecuteOnPause()
{
_alertingService.OnPause();
_isExecutedSuccesful.Set();
}
Run Code Online (Sandbox Code Playgroud)
有趣且最有意义的部分的片段:
public abstract class AdministratorServiceBase
{
protected readonly IAdminLayer AdminLayer;
protected readonly ServiceBase Service;
public Timer ServiceTimer = new Timer();
protected AutoResetEvent ResetEvent = new AutoResetEvent(true);
protected AdministratorServiceBase(IAdminLayer adminLayer, ServiceBase service, string name, string logname, string logsource, string version)
{
// Removed irrelevant implementation
ServiceTimer.Elapsed += ServiceTimerElapsed;
}
public virtual void OnStart()
{
try { // Removed irrelevant implementation }
catch (Exception ex)
{
HandleException(" detected a failure (trying to start).", ex, true, true);
}
}
// Same story for the other service methods...
public virtual void OnPause() {}
public virtual void OnContinue() {}
// ..
// ..
}
Run Code Online (Sandbox Code Playgroud)
如何在真正的 WindowsService 类中使用服务类
(这是视觉基础,但这不会有太大区别)
Public Class Service1
Private ReadOnly _alertingService As AdministratorAlertingService = New AdministratorAlertingService(AdminLayer.GetSingleInstance(), Me)
Protected Overrides Sub OnStart(ByVal args() As String)
_alertingService.OnStart()
End Sub
Protected Overrides Sub OnPause()
_alertingService.OnPause()
End Sub
// etc etc
End Class
Run Code Online (Sandbox Code Playgroud)
两天时间重构了4个windows服务,好处无法估量!TDD 确实帮助我交付了质量。
我的 Windows Service 类是Service1Visual Basic 类。它创建一个 的实例
AdministratorAlertingService。
Private ReadOnly _alertingService As AdministratorAlertingService =
New AdministratorAlertingService(/* parameters /*)
Run Code Online (Sandbox Code Playgroud)
该AdministratorAlertingService扩展AdministratorServiceBaseClass包含我的其他 Windows 服务也具有的共享行为(计时器、启动、暂停、停止)。
如果您只有一个 Windows 服务,那么您当然不需要基类。
在我的单元测试中,我创建了一个新的 SuT(被测主题),在本例中是一个新的 SuT,AdministratorAlertingService我使用AutoResetEvent. Windows 服务完成的“实际工作”是在专门针对这些类的单元测试中进行模拟和测试的。
这样您就可以(并且应该)TDD 您的 Windows 服务。它将显着减少 Windows 服务的开发测试周期。
您可以选择将集成测试添加到您的测试套件中以测试完整的功能:您委托的手写启动、暂停、停止行为,其中您不模拟执行实际工作的类的功能。我通过管理员服务赢得了最多的 TDD。
我希望它有帮助!享受你的 TDD 冒险吧。
| 归档时间: |
|
| 查看次数: |
1540 次 |
| 最近记录: |