- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个关于设计类以便测试友好的最佳方法的问题。假设我有一个 OrderService 类,用于下新订单、检查订单状态等。该类将需要访问客户信息、库存信息、运输信息等。因此 OrderService 类将需要使用 CustomerService、InventoryService 和 ShippingService。每个服务还有自己的后备存储库。
将 OrderService 类设计为易于测试的最佳方法是什么?我见过的两种常用模式是依赖注入(inject)和服务定位器。对于依赖注入(inject),我会做这样的事情:
class OrderService
{
private ICustomerService CustomerService { get; set; }
private IInventoryService InventoryService { get; set; }
private IShippingService ShippingService { get; set; }
private IOrderRepository Repository { get; set; }
// Normal constructor
public OrderService()
{
this.CustomerService = new CustomerService();
this.InventoryService = new InventoryService();
this.ShippingService = new ShippingService();
this.Repository = new OrderRepository();
}
// Constructor used for testing
public OrderService(
ICustomerService customerService,
IInventoryService inventoryService,
IShippingService shippingService,
IOrderRepository repository)
{
this.CustomerService = customerService;
this.InventoryService = inventoryService;
this.ShippingService = shippingService;
this.Repository = repository;
}
}
// Within my unit test
[TestMethod]
public void TestSomething()
{
OrderService orderService = new OrderService(
new FakeCustomerService(),
new FakeInventoryService(),
new FakeShippingService(),
new FakeOrderRepository());
}
这样做的缺点是,每次我创建一个我在测试中使用的 OrderService 对象时,都需要大量代码来调用我的测试中的构造函数。我的服务类最终还为它们使用的每个服务和存储库类提供了一堆属性。当我扩展我的程序并在各种服务和存储库类之间添加更多依赖项时,我必须返回并向我已经创建的类的构造函数添加越来越多的参数。
对于服务定位器模式,我可以这样做:
class OrderService
{
private CustomerService CustomerService { get; set; }
private InventoryService InventoryService { get; set; }
private ShippingService ShippingService { get; set; }
private OrderRepository Repository { get; set; }
// Normal constructor
public OrderService()
{
ServiceLocator serviceLocator = new ServiceLocator();
this.CustomerService = serviceLocator.CreateCustomerService()
this.InventoryService = serviceLocator.CreateInventoryService();
this.ShippingService = serviceLocator.CreateShippingService();
this.Repository = serviceLocator.CreateOrderRepository();
}
// Constructor used for testing
public OrderService(IServiceLocator serviceLocator)
{
this.CustomerService = serviceLocator.CreateCustomerService()
this.InventoryService = serviceLocator.CreateInventoryService();
this.ShippingService = serviceLocator.CreateShippingService();
this.Repository = serviceLocator.CreateOrderRepository();
}
}
// Within a unit test
[TestMethod]
public void TestSomething()
{
OrderService orderService = new OrderService(new TestServiceLocator());
}
我喜欢服务定位器模式在调用构造函数时如何减少代码,但它也提供了较少的灵 active 。
设置我的服务类的推荐方法是什么,这些类依赖于其他几个服务和存储库,以便可以轻松地对其进行测试?我上面展示的任何一种或两种方法都不错,还是有更好的方法?
最佳答案
只是一个非常快速的回答,让您走上正确的轨道。根据我的经验,如果您的目标是易于测试的代码,您往往会得到干净可维护的代码作为一个很好的副作用。 :-)
要记住的一些要点:
SOLID 原则将真正帮助您创建良好、干净、可测试的代码。
(S + O + I) 将这个服务分解成更小的服务,只做一件事,因此只有一个改变的理由。至少下订单和检查订单状态是完全不同的事情。如果你仔细考虑一下,你真的不需要遵循最明显的步骤(例如检查信用->检查库存->检查运输),其中一些可以乱序完成 - 但那是另一回事可能需要不同商业模式的故事。无论如何,如果您确实需要,您可以使用 Facade 模式在这些较小的服务之上创建一个简化的 View 。
使用 IoC 容器(例如 unity)
使用模拟框架(例如 Moq)
服务定位器模式实际上被认为是一种反模式/代码味道 - 所以请不要使用它。
您的测试应该使用与实际代码相同的路径,因此摆脱“普通构造函数”。第一个示例中的“用于测试的构造函数”是您的构造函数的外观。
不要在您的类中实例化所需的服务 - 它们应该作为接口(interface)传入。 IoC 容器会帮你处理这部分。这样你就遵循了 Solid 中的 D(依赖倒置原则)
尽可能避免直接在您自己的类中使用/引用静态类/方法。在这里,我谈论的是直接使用 DateTime.Now() 之类的东西,而不是先将它们包装在接口(interface)/类中。例如,在这里您可以有一个带有 GetLocalTime() 方法的 IClock 接口(interface),您的类可以使用该方法而不是直接使用系统函数。这允许您在运行时注入(inject)一个 SystemClock 类,在测试期间注入(inject)一个 MockClock。通过这样做,您可以完全控制返回到被测系统/类的确切时间。这一原则显然适用于所有其他可能返回不可预测结果的静态引用。我知道它增加了你需要传递到你的类中的另一件事,但它至少使预先存在的依赖关系明确并防止目标帖子在测试期间不断移动(不必诉诸黑魔法,如 MS Fakes)。
这是次要的一点,但是你的私有(private)属性应该是字段
关于c# - 测试友好的架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33131858/
为了我们公司的 SEO 需求,我们需要通过 301 将一些 SEO URL 更改为另一个 URL。 示例: /seo/keywords-1-2-3/ 到 /seo/mynew301page-1-2-3
使已经开发的 Vue 应用程序对 SEO 友好的最简单方法是什么(搜索引擎可以读取所有标题元标记)。 我已经研究过 NUXT,我将不得不再次重新构建整个过程,而且除了 SSR(服务器端渲染)部分之外,
我正在使用 Azure 数据库进行一些数据库管理,我需要执行查询,例如删除数据库中的所有约束。 sp_MSForEachTable 在使用 Azure 数据库时不可用,因此我正在采用不同的方法来实现此
在我的研究中,我发现了 2 种方法。 两者都需要修改 Global.Asax 中的 Application_BeginRequest 过程,您可以在其中运行代码来进行实际的 URL 映射(我的数据库
例如我有这个字符串: make no@ sen# `se ! 我会像这样生成 url make-no-sen-se! 我有这个: var value = $('.titleVal').val(
我有一个网站,我想开始使用友好的 URL。 所以不是: http://server.com/company.php?id=12 我可以使用: http://server.com/company/ste
我正在用 pandas 编写一些数据分析管道。我一直在使用的数据框中的一列是由自定义编写的类的对象组成的,每个类都用一个字符串初始化,我用正则表达式从中读取各种信息并存储在对象的属性中。子类结构类似于
这个问题已经存在: C++ create new windows command [closed] 关闭 4 年前。 我正在尝试创建一个 C++ 控制台应用程序并创建新命令。 我想做的事的例子:在终
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 8 年前。 Improve
我一直在尝试为 prestashop 中的产品创建第二个 url 重写选项.在 SEO 和 URL 部分的标准 Prestashop 安装中,我得到了以下产品 url 构建: {category:/}
我在使用重写引擎通过友好的 url 实现我的目标时遇到了一些问题。 基本上我有以下结构:- 索引.php - 吃下 - index.php 我在主索引中的链接是这样的:下载/index.php?dow
我真的不喜欢在链接中使用选择/选项元素: 但是他们已经找到了作为一种选择进入设计师组合的方式,并尽我所能劝阻他们不要使用它们,我知道如果没有谷歌的力量,我会输掉这场战斗,而且“这对 SEO 不利”。
dispose: function() { var disposer; while (disposer = this._disposers.shift()) { // expected
我将 Heroku 应用程序上的自定义域更改为新域。现在我将创建一个新的 Heroku 应用程序,它的唯一目的是重定向到第一个应用程序。 我在 Google Webmasters 中读到我应该像这样进
我有一个类。这个类有2个字段。 我有一个整数数组。我的任务是重载友好的“+”运算符,以便可以将数组中的字段值与数组元素的值相加。 例如: class Test { public: double
这个问题在这里已经有了答案: Encode URL in JavaScript (22 个答案) 关闭 9 年前。 您好,我有这个 URL(顶部),我正在尝试与“pinterest”一起使用,他们会
jQuery 模式对话框 seo 友好吗?如果不是,我们可以进行哪些更改,以便爬虫可以轻松读取模态对话框中的内容? 提前致谢。 编辑:抱歉忘记提及模式中的内容来自服务器端。所以它也使用 ajax。 最
这是我的 main.js 文件: jQuery(function($) { $('LI.tree-item-name').has('ul').click(function() { if (
static func randomShape() -> Shape { // Find out count of possible shapes var maxValue = 0
我正在构建一个通过 index.php 运行所有代码的网站。 例如 index.php?controller=something&id=01234。 我想使用 PHP 创建友好的 URL,所以我这样做
我是一名优秀的程序员,十分优秀!