ABP单元测试

发表于:2018-9-30 10:26  作者:*Hunter   来源:51testing采编

字体: | 上一篇 | 下一篇 |我要投稿 | 推荐标签: 单元测试

  一、介绍
  在本文中,我将介绍如何为基于ASP.NET Boilerplate的项目创建单元测试。 我将使用本文开发的相同的应用程序(使用AngularJs,ASP.NET MVC,Web API和EntityFramework来构建NLayered单页面Web应用程序)而不是创建要测试的新应用程序。 解决方案结构就是这样:
   
  我们将测试项目的应用服务。 它包括SimpleTaskSystem.Core,SimpleTaskSystem.Application和SimpleTaskSystem.EntityFramework项目。 您可以阅读本文,了解如何构建此应用程序。 在这里,我将专注于测试。
  二、创建一个项目
  我创建了一个名为SimpleTaskSystem.Test的新类库项目,并添加了以下nuget包:
  Abp.TestBase: 提供一些基类,使基于ABP的项目更容易测试。
  Abp.EntityFramework: 我们使用EntityFramework 6.x作为ORM。
  Effort.EF6: 可以为易于使用的EF创建一个假的,内存中的数据库
  xunit: 我们将使用的测试框架。 另外,添加了xunit.runner.visualstudio包以在Visual Studio中运行测试。 当我写这篇文章时,这个包是预先释放的。 所以,我在nuget包管理器对话框中选择了'Include Prerelease'。
  Shouldly: 此库容易编写断言。
  xunit.runner.visualstudio: 不安装此库,发现不了测试方法
  当我们添加这些包时,它们的依赖关系也将被自动添加。 最后,我们应该添加对SimpleTaskSystem.Application,SimpleTaskSystem.Core和SimpleTaskSystem.EntityFramework程序集的引用,因为我们将测试这些项目。
  二、准备一个基础测试类
  1,为了更容易地创建测试类,我将创建一个准备假数据库连接的基类:
  /// <summary>
  /// 这是所有测试类的基础类。
  /// 它准备了ABP系统,模块和一个伪造的内存数据库。
  /// 具有初始数据的种子数据库(<see cref =“SimpleTaskSystemInitialDataBuilder”/>)。
  /// 提供使用DbContext轻松使用的方法。
  /// </summary>
  public abstract class SimpleTaskSystemTestBase : AbpIntegratedTestBase<SimpleTaskSystemTestModule>
  {
  protected SimpleTaskSystemTestBase()
  {
  //种子初始数据
  UsingDbContext(context => new SimpleTaskSystemInitialDataBuilder().Build(context));
  }
  protected override void PreInitialize()
  {
  //假DbConnection使用Effort!
  LocalIocManager.IocContainer.Register(
  Component.For<DbConnection>()
  .UsingFactoryMethod(Effort.DbConnectionFactory.CreateTransient)
  .LifestyleSingleton()
  );
  base.PreInitialize();
  }
  public void UsingDbContext(Action<SimpleTaskSystemDbContext> action)
  {
  using (var context = LocalIocManager.Resolve<SimpleTaskSystemDbContext>())
  {
  context.DisableAllFilters();
  action(context);
  context.SaveChanges();
  }
  }
  public T UsingDbContext<T>(Func<SimpleTaskSystemDbContext, T> func)
  {
  T result;
  using (var context = LocalIocManager.Resolve<SimpleTaskSystemDbContext>())
  {
  context.DisableAllFilters();
  result = func(context);
  context.SaveChanges();
  }
  return result;
  }
  }
  该基类继承了AbpIntegratedTestBase,它是一个初始化了ABP系统的基类,定义了 protected IIocManager LocalIocManager { get; } 。每个测试都会使用这个专用的IIocManager。因此,测试之间是相互隔离的。
  在SimpleTaskSystemTestBase的PreInitialize方法中,我们正在使用Effort注册DbConnection到依赖注入系统(PreInitialize方法用于运行一些代码,仅用于ABP初始化)。 我们将其注册为Singleton(用于LocalIocConainer)。 因此,即使我们在同一测试中创建了多个DbContext,测试中也将使用相同的数据库(和连接)。
  SimpleTaskSystemTestBase的UsingDbContext方法使得当我们需要直接使用DbContect来处理数据库时,可以更容易地创建DbContextes。 在构造函数中,我们使用它。 另外,我们将在测试中看到如何使用它。
  SimpleTaskSystemDbContext必须具有获取DbConnection的构造函数才能使用该内存数据库。 所以,我添加下面的构造函数接受一个DbConnection:
  public class SimpleTaskSystemDbContext : AbpDbContext
  {
  public virtual IDbSet<Task> Tasks { get; set; }
  public virtual IDbSet<Person> People { get; set; }
  public SimpleTaskSystemDbContext()
  : base("Default")
  {
  }
  public SimpleTaskSystemDbContext(string nameOrConnectionString)
  : base(nameOrConnectionString)
  {
  }
  //这个构造函数用于测试
  public SimpleTaskSystemDbContext(DbConnection connection)
  : base(connection, true)
  {
  }
  }
  在SimpleTaskSystemTestBase的构造函数中,我们还在数据库中创建一个初始数据。 这很重要,因为一些测试需要数据库中存在的数据。 SimpleTaskSystemInitialDataBuilder类填充数据库,如下所示:
  public class SimpleTaskSystemInitialDataBuilder
  {
  public void Build(SimpleTaskSystemDbContext context)
  {
  //添加一些人
  context.People.AddOrUpdate(
  p => p.Name,
  new Person {Name = "Isaac Asimov"},
  new Person {Name = "Thomas More"},
  new Person {Name = "George Orwell"},
  new Person {Name = "Douglas Adams"}
  );
  context.SaveChanges();
  //添加一些任务
  context.Tasks.AddOrUpdate(
  t => t.Description,
  new Task
  {
  Description = "my initial task 1"
  },
  new Task
  {
  Description = "my initial task 2",
  State = TaskState.Completed
  },
  new Task
  {
  Description = "my initial task 3",
  AssignedPerson = context.People.Single(p => p.Name == "Douglas Adams")
  },
  new Task
  {
  Description = "my initial task 4",
  AssignedPerson = context.People.Single(p => p.Name == "Isaac Asimov"),
  State = TaskState.Completed
  });
  context.SaveChanges();
  }
  }
  我们所有的测试类都将从SimpleTaskSystemTestBase继承。 因此,所有测试都将通过使用具有初始数据的假数据库初始化ABP来启动。 我们还可以为此基类添加常用的帮助方法,以便使测试更容易。
  2,我们应该创建一个专门用于测试的模块。 这是SimpleTaskSystemTestModule在这里:
  [DependsOn(
  typeof(SimpleTaskSystemDataModule),
  typeof(SimpleTaskSystemApplicationModule)
  )]
  public class SimpleTaskSystemTestModule : AbpModule
  {
  }
  此模块仅定义依赖模块,将进行测试。
  三、创建第一个测试
  我们将创建第一个单元测试来测试TaskAppService类的CreateTask方法。
  TaskAppService类和CreateTask方法定义如下:
  public class TaskAppService : ApplicationService, ITaskAppService
  {
  private readonly ITaskRepository _taskRepository;
  private readonly IRepository<Person> _personRepository;
  public TaskAppService(ITaskRepository taskRepository, IRepository<Person> personRepository)
  {
  _taskRepository = taskRepository;
  _personRepository = personRepository;
  }
  public void CreateTask(CreateTaskInput input)
  {
  Logger.Info("Creating a task for input: " + input);
  var task = new Task { Description = input.Description };
  if (input.AssignedPersonId.HasValue)
  {
  task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value);
  }
  _taskRepository.Insert(task);
  }
  //...other methods
  }
  我们先创建一个测试来测试CreateTask方法。
   public class TaskAppService_Tests : SimpleTaskSystemTestBase
  {
  private readonly ITaskAppService _taskAppService;
  public TaskAppService_Tests()
  {
  //创建被测试的类(SUT(Software Under Test) - 被测系统)
  _taskAppService = LocalIocManager.Resolve<ITaskAppService>();
  }
  [Fact]
  public void Should_Create_New_Tasks()
  {
  //准备测试
  var initialTaskCount = UsingDbContext(context => context.Tasks.Count());
  var thomasMore = GetPerson("Thomas More");
  //运行SUT
  _taskAppService.CreateTask(
  new CreateTaskInput
  {
  Description = "my test task 1"
  });
  _taskAppService.CreateTask(
  new CreateTaskInput
  {
  Description = "my test task 2",
  AssignedPersonId = thomasMore.Id
  });
  //检查结果
  UsingDbContext(context =>
  {
  context.Tasks.Count().ShouldBe(initialTaskCount + 2);
  context.Tasks.FirstOrDefault(t => t.AssignedPersonId == null && t.Description == "my test task 1").ShouldNotBe(null);
  var task2 = context.Tasks.FirstOrDefault(t => t.Description == "my test task 2");
  task2.ShouldNotBe(null);
  task2.AssignedPersonId.ShouldBe(thomasMore.Id);
  });
  }
  private Person GetPerson(string name)
  {
  return UsingDbContext(context => context.People.Single(p => p.Name == name));
  }
  }

   上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。

【直播预售】接口测试行业大佬带你从青铜上王者>>立即查看
21/212>

评 论

论坛新帖

顶部 底部


建议使用IE 6.0以上浏览器,800×600以上分辨率,法律顾问:上海瀛东律师事务所 张楠律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2018, 沪ICP备05003035号
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪公网安备 31010102002173号

51Testing官方微信

51Testing官方微博

扫一扫 测试知识全知道