【发布时间】:2014-09-02 16:48:50
【问题描述】:
我被指派为遗留系统提供帮助;该系统在整个应用程序中都引用了第三方库(超过2000次)。应用程序中没有单个单元测试,这是一个关键任务系统。
我想做的是重构代码,这样第三方类就不会在整个应用程序中被引用。我还想围绕我可以控制的代码介绍单元测试。
使用第 3 方 dll 的代码示例如下所示(第 3 方类是 Controller 和 Tag):
public class Processor
{
private Controller _clx;
private Tag _tag;
public bool Connect(string ip, string slot, int timeout, bool blockWrites, string tagName)
{
_clx = new Controller(ip, slot, timeout);
if (_clx != null)
{
_clx.Connect();
if (_clx.IsConnected)
{
if (tagName != null)
{
_tag = new Tag(_clx, tagName, ATOMIC.DINT);
return ((_tag.ErrorCode == 0) && _tag.Controller.IsConnected);
}
_tag = new Tag {Controller = _clx, DataType = ATOMIC.DINT, Length = 1};
return (_tag.Controller.IsConnected);
}
}
return false;
}
}
我已经能够创建一个包装类来帮助我删除第 3 方 dll 的所有引用,现在所有调用都通过我的包装,我的包装是唯一调用第 3 方 dll 的代码。
public class ControllerWrapper
{
public ControllerWrapper(string ip, string slot, int timeout)
{
Controller = new Controller(ip,slot,timeout);
}
public Controller Controller { get; set; }
}
public class TagWrapper
{
public Tag Tag { get; set; }
public TagWrapper()
{
}
public TagWrapper(ControllerWrapper clx, string tagName, ATOMIC datatype)
{
Tag = new Tag(clx.Controller, tagName,datatype);
}
}
现在我的处理器类看起来像:
public class Processor
{
private ControllerWrapper _clx;
private TagWrapper _tag;
public bool Connect(string ip, string slot, int timeout, bool blockWrites, string tagName)
{
_clx = new ControllerWrapper(ip, slot, timeout);
if (_clx != null)
{
_clx.Controller.Connect();
if (_clx.Controller.IsConnected)
{
if (tagName != null)
{
_tag = new TagWrapper(_clx, tagName, ATOMIC.DINT);
return ((_tag.Tag.ErrorCode == 0) && _tag.Tag.Controller.IsConnected);
}
_tag = new TagWrapper {Tag = {Controller = _clx.Controller, DataType = ATOMIC.DINT, Length = 1}};
return (_tag.Tag.Controller.IsConnected);
}
}
return false;
}
}
我的问题是我仍然无法对 Processor.Connect(...) 进行单元测试
附加信息 --
- 这是一个 winforms 应用程序 .NET 2.0。
- 没有使用任何 DI 或 IOC 工具。
- 具体的 Tag 对象需要具体的 Controller 对象。
- 第 3 方 dll 无法在测试环境中使用,因为它使用 IP 并尝试连接到控制器。
我想我不明白的是如何从 Connect 方法中创建标签和控制器,以便我可以在单元测试中拥有假标签和假控制器,但拥有真正的标签和控制器在生产代码中。
我已经玩了大约 4 天了,并实现了许多不同的版本,但仍然不知所措。
我已经尝试过如下的构建器类:
public static class TagBuilder
{
public static ITagProxy BuildTag()
{
return new TagProxy().CreateTag();
}
public static ITagProxy BuildTag(IControllerProxy clx, string tagName, ATOMIC datatype)
{
return new TagProxy().CreateTag(clx, tagName, datatype);
}
}
使用 ITagProxy 之类的
public interface ITagProxy
{
Tag Tag { get; set; }
ITagProxy CreateTag();
ITagProxy CreateTag(IControllerProxy clx, string tagName, ATOMIC dataType);
}
和 ControllerProxy 类似:
public interface IControllerProxy
{
Controller Controller { get; set; }
IControllerProxy CreateController(string ip, string slot, int timeout );
}
现在处理器代码如下所示:
public class Processor
{
private IControllerProxy _clx;
private ITagProxy _tag;
public virtual bool Connect(string ip, string slot, int timeout, bool blockWrites, string tagName)
{
_clx = CreateController(ip, slot, timeout);
if (_clx != null && _clx.Controller != null)
{
_clx.Controller.Connect();
if (_clx.Controller.IsConnected)
{
// check this connection carefully, if it fails the controller is not in the slot configured
if (tagName != null)
{
// use supplied Tag Name to to a qualified connection
_tag = TagBuilder.BuildTag(_clx, tagName, ATOMIC.DINT);
return ((_tag.Tag.ErrorCode == 0) && _tag.Tag.Controller.IsConnected);
}
_tag = TagBuilder.BuildTag();
_tag.Tag.Controller = _clx.Controller;
_tag.Tag.Length = 1;
return (_tag.Tag.Controller.IsConnected);
}
}
return false;
}
public virtual IControllerProxy CreateController(string ip, string slot, int timeout)
{
if (_clx == null)
_clx = new ControllerProxy();
return _clx.CreateController(ip, slot, timeout);
}
}
但还是依赖于具体的Tag和Controller。
如何让代码不依赖于具体标签和控制器?
【问题讨论】:
-
您仍在包装器中公开
Tag。如果您想要真正的隔离,那么您需要将代理类中的每个属性/方法完全包装起来,这样第三方Tag对象的存在只是该代理的一个实现细节。一旦你达到了这一点,那么你可以看看使用 DI 正确地创建对象。 -
感谢您的意见。它让我看到了我错过了什么。
标签: c# .net unit-testing