3

我已经阅读或尝试阅读太多关于此的“如何做”,但完全无处可去。统一?System.Web.Http.Dependencies?忍者?结构图?啊。我只想要一些简单有效的东西!我只是无法弄清楚目前的状态是什么。有非常不同的方法,示例似乎不完整。哎呀,最好的领导有一个示例项目......我无法在 VS2010 或 2012 中加载。ARG!我把一天中的 3/4 浪费在了我认为最多半小时的事情上,然后继续前进!简直是水管!

我有一个基于泛型的存储库来处理所有支持相同操作的许多数据集。

存储库

我想控制每个数据集绑定到哪个存储库。这将允许我将所有内容绑定到测试 XML 存储库,随着项目的推进将它们转换到 SQL 存储库。

我当然会很感激一些帮助,让这一切顺利进行!谢谢!

4

1 回答 1

3

听起来你正处于我几年前的状态。

请注意,如果您需要任何进一步的帮助,我会向您发送一些代码。很难把所有的代码都放在这里。

我将尝试解释我正在从事的项目中的当前架构。这篇文章有点啰嗦,但我试图让您大致了解使用 IOC 如何在许多方面为您提供帮助。

所以我使用Ninject。在尝试使用 Castle Windsor 一段时间后,我发现 Ninject 很容易启动和运行。Ninject 有一个很酷的网站,可以帮助您入门。

首先我的项目结构如下:(自上而下,它是MVC)

视图- 剃刀 ViewModel - 每个视图我使用 1 个视图模型

ViewModelBuilder - 为我的视图构建我的视图模型(用于从我的控制器中抽象代码,使我的控制器保持整洁)

AutoMapper - 将域实体映射到我的视图模型

控制器- 调用我的服务层来获取域实体

域实体- 我的域的表示

ServiceLayer(业务层) - 调用我的存储库层以获取域实体或这些实体的集合

再次使用 AutoMapper - 将我的第 3 方供应商的自定义类型映射到我的域实体中

RepositoryLayer - 对我的数据存储进行 CRUD 操作

这是一个层次结构,但域实体有点坐在一起,并在几个不同的层中使用。

注意:本文中提到的一些额外工具是:

AutoMapper - 将实体映射到其他实体 - 无需编写大量映射代码

Moq - 允许你模拟单元测试的东西。这在后面会提到。

现在,关于 Ninject。

每层都标有一个接口。必须这样做,这样 Ninject 才能对自己说。

当我发现 IVehicleRepository 将其注入真实的 VehicleRepository 时,或者如果我需要假货,甚至将其注入 FakeVehicleRepository。

(这与您的评论有关 - “这将允许我将所有内容绑定到测试 XML 存储库”)

现在每一层都有一个构造函数,以便 Ninject(或任何其他 IOC 容器)可以注入它需要的内容:

public VehicleManager(IVehicleRepository vehicleRepository)
{
    this._vehicleRepository = vehicleRepository;
}

VehicleManager 在我的 serviceLayer 中(不要与与 Web 服务有关的任何事情混淆)。服务层实际上就是我们所说的业务层。似乎很多人都在使用服务这个词。(尽管我认为这很烦人,因为它让我想到 Web 服务或 WCF 而不仅仅是业务层......无论如何......)

现在无需深入了解 Ninject 设置的细节,我的 NinjectWebCommon.cs 中的以下代码行告诉 ninject 要做什么:

kernel.Bind<IVehicleRepository>().To<VehicleRepository>().InRequestScope();

这说:

嘿 Ninject,当我要求 IVehicleRepository 时,请给我一个 VehicleRepository 的具体实现。

如前所述,我可以用 FakeVehicleRepository 替换 VehicleRepository,这样我就不必从真实数据库中读取数据。

因此,正如您现在可以想象的那样,每一层都只依赖于接口。

我不知道你做了多少单元测试,但你也可以想象,如果你想对你的服务层进行单元测试并且它对你的存储库层有具体的引用,那么你将无法进行单元测试,因为你实际上会击中你的存储库,因此从真实数据库中读取。

请记住,单元测试之所以称为单元测试,是因为它只测试一件事。因此,单位一词。所以因为一切都只知道接口,这意味着你可以在你的服务层测试一个方法并模拟存储库。

因此,如果您的服务层有这样的方法:

public bool ThisIsACar(int id)
{
   bool isCar = false;
   var vehicle = vehicleRepository.GetVehicleById(id);

   if(vehicle.Type == VehicleType.Car)
   {
       isCar = true;
   }
   else
   {
       isCar = false;
   }
}

您不希望调用 vehicleRepository,这样您就可以 Moq VehicleRepository 给您返回的内容。如果它实现了一个接口,你通常只能模拟东西。

So your unit test would look like this (some pseudo code here):
        [TestMethod]
        public void ServiceMethodThisIsACar_Returns_True_When_VehicleIsACar()
        {
            // Arrange
            _mockRepository.Setup(x => x.ThisIsACar(It.IsAny<int>)).returns(new Car with a type of VehicleType.Car)

            // Act
            var vehicleManager = new VehicleManager(_mockVehicleRepository.Object);
            var vehicle = vehicleManager.ThisIsACar(3);

            // Assert
            Assert.IsTrue(vehicle.VehicleType == VehicleType.Car)
        }

如您所见,此时非常简化,您只需在服务层中测试 IF 语句以确保结果正确。

您将在自己的单元测试中测试您的存储库,如果您正在使用它,可能会模拟实体框架工作。

所以,总的来说,我会说,使用任何 IOC 容器让你以最少的痛苦最快地启动和运行。

我还要说,尽你所能尝试和单元测试。这很好,有几个不同的原因。显然它会测试你编写的代码,但它也会立即显示你是否做了一些愚蠢的事情,比如新建一个具体的存储库。你会很快发现在你的单元测试中你不会有一个接口来模拟,这将导致你回去重构你的代码。

我发现使用 IOC 需要一段时间才能获得它。直到有一天它发出咔嗒声,它才会让你感到困惑。在那之后,它很容易让你想知道没有它你是如何生活的。

这是一个没有 Automapper Moq Fluent Validation Resharper 我无法忍受的列表 - 有些人讨厌它,我喜欢它,主要是因为它的单元测试 UI。

无论如何,这太长了。让我知道你的想法。

谢谢RuSs

于 2013-02-13T00:30:59.117 回答