如何对ServiceStack进行单元测试?

2024-02-26

我喜欢 SS,但我在尝试对我的业务层进行单元测试时摸不着头脑。我是单元测试和模拟的新手,并且一直在阅读 NSubstitute,因为这看起来像是一个有趣的模拟层。

我的文件结构大致如下:

MainAppHostProject*
|
 -AppStart
    -AppHost  <-- standard apphost

DtoProject*
|
 -HelloWorldDto  <-- simple POCO to 


ServiceLayerProject*
|
 -HelloWorldService  <-- service interface that merely passes/sends Dtos to/from business layer


BusinessLayerProject*
|
 -HelloWorldManager <-- logic to construct response and this class extends 'Service' (letting me access Db, session, etc)...sidenote: maybe i shouldve called this a HelloWorldRepository?
 -CustomAuthProvider
 -CustomUserSession


DaoProject*
|
 -HelloWorldDao  <-- POCO of table structure

Apphost 指向 HelloWorldService 程序集,并将 SQL Server 数据库注册为标准。

一切实际上都很好,我已经能够以更清晰的方式构建逻辑。不幸的是,我希望开始单元测试,但我不知道如何解耦数据库。

我尝试在内存数据库中注册一个假的,但后来我认为我使用代码以 SQL Server 与 SQLite 方式获取身份等的方式存在不兼容问题。

// container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(":memory:", false, SqliteOrmLiteDialectProvider.Instance));
// container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(":memory:", false, SqlServerDialect.Provider));

我只想解耦和单元测试。有什么想法吗?

***更新

public class UnitTest1
{
    private Container container;

    [TestMethod]
    public void TestMethod1()
    {
        container = new Container();

        // container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider));
        // sqlite didnt work so attempting with a real DB for now
        var connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=XXX;Integrated Security=True";
        container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider));

        // dependencies are injecting ok 
        container.RegisterAutoWiredAs<FeedbackRepo, IFeedbackRepo>();

        // service is autowiring --> leading to good injections
        container.RegisterAutoWired<FeedbackService>();

        var service = container.Resolve<FeedbackService>();
        service.SetResolver(new BasicResolver(container));

        // unit test is working well  
        var request = new DTO.FeedbackDto { Message = "test" };
        bool result = service.Post(request);
   }
}

目前正在尝试让“Db”在我的派生服务类中停止为空。


如果您想单独对 ServiceStack 服务进行单元测试,可以采用几种不同的方法。基地Service https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/Service.cs类本身只是一个简单的 C# 类,它允许您手动或使用内置 IOC 容器定义和注入依赖项。

我们将使用这个来说明这两种方法简单的单元测试示例 https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.Endpoints.Tests/UnitTestExample.cs测试这个简单的服务:

DTOs

public class FindRockstars
{
   public int? Aged { get; set; }
   public bool? Alive { get; set; }
}

public class GetStatus
{
   public string LastName { get; set; }
}

public class RockstarStatus
{
   public int Age { get; set; }
   public bool Alive { get; set; }
}

public class Rockstar
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int? Age { get; set; }
}

执行

public class SimpleService : Service
{
   public IRockstarRepository RockstarRepository { get; set; }

   public List<Rockstar> Get(FindRockstars request)
   {
      return request.Aged.HasValue
          ? Db.Select<Rockstar>(q => q.Age == request.Aged.Value)
          : Db.Select<Rockstar>();
   }

   public RockstarStatus Get(GetStatus request)
   {
      var rockstar = RockstarRepository.GetByLastName(request.LastName);
      if (rockstar == null)
          throw HttpError.NotFound("'{0}' is not a Rockstar".Fmt(request.LastName));

      var status = new RockstarStatus
      {
          Alive = RockstarRepository.IsAlive(request.LastName)
      }.PopulateWith(rockstar); //Populates with matching fields

      return status;
   }
}

该服务提供 2 种操作,FindRockstars这使得数据库直接在服务类本身中进行查询,并且GetStatus它使用存储库来代替其所有数据访问。

使用内存数据库

如果您正在访问Db直接在您的服务实现中,您将希望使用真实的数据库,因为ADO.NET IDbConnection http://msdn.microsoft.com/en-us/library/system.data.idbconnection.aspx需要付出很大的努力来嘲笑。您可以使用内置 IOC,以与在 ServiceStack 本身中注册依赖项相同的方式执行此操作。对于单元测试,我们可以在没有 AppHost 的情况下通过使用新的Container在你的TestFixtureSetup, e.g:

测试设置

private ServiceStackHost appHost;

[TestFixtureSetUp]
public void TestFixtureSetUp()
{
    appHost = new BasicAppHost().Init();
    var container = appHost.Container;

    container.Register<IDbConnectionFactory>(
        new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider));

    container.RegisterAutoWiredAs<RockstarRepository, IRockstarRepository>();

    container.RegisterAutoWired<SimpleService>();

    using (var db = container.Resolve<IDbConnectionFactory>().Open())
    {
        db.DropAndCreateTable<Rockstar>();
        db.InsertAll(SeedData);
    }
}

[TestFixtureTearDown]
public void TestFixtureTearDown()
{
    appHost.Dispose();
}

完成所有设置后,我们现在可以像普通的 C# 类一样独立于 ServiceStack 本身来测试服务:

[Test]
public void Using_in_memory_database()
{
    //Resolve the autowired service from IOC and set Resolver for the base class
    var service = appHost.Container.Resolve<SimpleService>(); 

    var rockstars = service.Get(new FindRockstars { Aged = 27 });

    rockstars.PrintDump(); //Print a dump of the results to Console

    Assert.That(rockstars.Count, Is.EqualTo(SeedData.Count(x => x.Age == 27)));

    var status = service.Get(new GetStatus { LastName = "Vedder" });
    Assert.That(status.Age, Is.EqualTo(48));
    Assert.That(status.Alive, Is.True);

    status = service.Get(new GetStatus { LastName = "Hendrix" });
    Assert.That(status.Age, Is.EqualTo(27));
    Assert.That(status.Alive, Is.False);

    Assert.Throws<HttpError>(() =>
        service.Get(new GetStatus { LastName = "Unknown" }));
}

手动注入依赖

如果您不希望单元测试使用内存数据库,则可以选择模拟依赖项。在此示例中,我们将使用独立的模拟,但您可以通过使用模拟库来减少样板文件,例如Moq https://github.com/Moq/moq反而。

public class RockstarRepositoryMock : IRockstarRepository
{
    public Rockstar GetByLastName(string lastName)
    {
        return lastName == "Vedder"
            ? new Rockstar(6, "Eddie", "Vedder", 48)
            : null;
    }

    public bool IsAlive(string lastName)
    {
        return lastName == "Grohl" || lastName == "Vedder";
    }
}

[Test]
public void Using_manual_dependency_injection()
{
    var service = new SimpleService
    {
        RockstarRepository = new RockstarRepositoryMock()
    };

    var status = service.Get(new GetStatus { LastName = "Vedder" });
    Assert.That(status.Age, Is.EqualTo(48));
    Assert.That(status.Alive, Is.True);

    Assert.Throws<HttpError>(() =>
        service.Get(new GetStatus { LastName = "Hendrix" }));
}

此示例不需要容器,因为我们手动注入所有依赖项。我还将此示例添加到测试维基 https://github.com/ServiceStack/ServiceStack/wiki/Testing docs.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何对ServiceStack进行单元测试? 的相关文章

  • 更改迁移中的自动​​增量值(PostgreSQL 和 SQLite3)

    我有一个托管在 Heroku 上的项目 想要更改表的自动增量起始值 我在本地使用 SQLite3 Heroku 使用 PostgreSQL 这是我在迁移中所拥有的 class CreateMytable lt ActiveRecord Mi
  • 如何在使用连接池时强制 SqlConnection 物理关闭?

    我明白 如果我实例化一个 SqlConnection 对象 我实际上是从连接池中获取一个连接 当我调用 Open 时 它将打开连接 如果我对该 SqlConnection 对象调用 Close 或 Dispose 方法 它将返回到连接池 但
  • 将 UUID 存储为 base64 字符串

    我一直在尝试使用 UUID 作为数据库键 我希望占用尽可能少的字节数 同时仍然保持 UUID 表示形式的可读性 我认为我已经使用 base64 将其减少到 22 个字节 并删除了一些尾随的 这些 对于我的目的来说似乎没有必要存储 这种方法有
  • Akka.net 和单元测试

    我想使用 Akka net TestKit 编写单元测试 但我有一个问题 我有一个 SubscriptionService 类 它负责将消息传输给选定的参与者 public class SubscriptionService Receive
  • SQL 删除表并重新创建并保留数据

    在我们最初的设计中 我们搞砸了表中的外键约束 现在表已充满数据 我们无法在不删除表中所有记录的情况下更改它 我能想到的唯一解决方案是创建一个备份表并将所有记录放在那里 然后删除所有记录 更改表并开始将它们添加回来 还有其他 更好 的想法吗
  • sql server 按组排名

    问题看似简单 但我却无法理解 这是针对 sql 服务器的 what I have in a table What I need as a output cksum id cksum id 2162514679 204 2162514679
  • 使用 SQLITE 按最近的纬度和经度坐标排序

    我必须获得一个 SQLite SQL 语句 以便在给定初始位置的情况下按最近的纬度和经度坐标进行排序 这是我在 sqlite 数据库中的表的例句 SELECT id name lat lng FROM items EXAMPLE RESUL
  • 对多个数据库执行 SQL 查询

    我知道我的帖子与该论坛中的其他帖子的标题非常相似 但我真的找不到我需要的答案 这是我的问题 我的 Windows Server 上运行着 SQL Server 在我的 SQL Server 中 我有大约 30 个数据库 它们都具有相同的表和
  • MySQL 按重复项从上到下排序

    我有一个lammer问题 因为我不是mysql专业人士 我有类似的字段 id color 1 red 2 green 3 yellow 4 green 5 green 6 red 我想按重复项进行分组 最常见的重复项先进行分组 所以应该这样
  • 使用 servicestack 如何防止 cookie 添加到响应中?

    我可以在事后删除cookie 方法如下 public override void Configure Funq Container container ResponseFilters Add req res dto gt HttpListe
  • SQLite .NET 性能,如何加快速度?

    在我的系统上 约 86000 个 SQLite 插入需要长达 20 分钟 意味着每秒约 70 个插入 我要做数百万 我怎样才能加快速度 对每一行的 SQLiteConnection 对象调用 Open 和 Close 会降低性能吗 交易有帮
  • 跨多个表进行搜索,并在结果行中显示表名称

    如何构建 SQL 语句以跨多个平面不相关的表运行 并使用选择结果和结果来自的表的名称显示结果 这种情况是这样的 我有几个表 每个表都有相同的列名 这是我从外部各方收到的数据 并将其存储在不同的表中 相同的表看起来像 Table 1 pid
  • 用更轻的解决方案替换完整的 ORM(JPA/Hibernate):推荐的加载/保存模式?

    我正在开发一个新的 Java Web 应用程序 并且正在探索保存数据的新方法 对我来说是新方法 我主要有 JPA 和 Hibernate 的经验 但是 除了简单的情况之外 我认为这种完整的 ORM 可能会变得相当复杂 另外 我不太喜欢和他们
  • SQLite插入大量记录时出现问题

    我试图使用 SQLite3 shell 在某个表中插入 15530 条记录 但出现该错误 我搜索了解决方案 SQLITE MAX COMPOUND SELECT 默认为 500 是原因 但我不知道如何使用 Shell 更改它 错误 复合 S
  • 自加入表

    我有一张像这样的桌子 Employee name salary a 10000 b 20000 c 5000 d 40000 我想获取所有工资高于A工资的员工 我不想使用任何嵌套或子查询 在采访中被问及并暗示是使用自连接 我真的不知道如何实
  • 月份增量查询

    我想通过添加 1 个月来更新数据库中的月份 但我不知道如何在以下存储过程查询中添加月份 我不擅长 sql 请检查它 ALTER PROCEDURE dbo ChangePassword password varchar 20 epasswo
  • 执行带有 EXCEPTION 的 PostgreSQL 查询会导致两条不同的错误消息

    我有一个 PostgreSQL 查询 其中包含事务和列重复时的异常 BEGIN ALTER TABLE public cars ADD COLUMN top speed text EXCEPTION WHEN duplicate colum
  • 使用间隔阈值对不同的连续时间戳记录进行分组

    我有一系列间歇性间隔的带有时间戳的 GPS 坐标 我正在使用 PostGIS 将它们渲染到地图画布上 为了渲染它们 需要使用 PostGIS 中的 ST MakeLine 聚合函数将点聚合成线 从而在地图上留下 GPS 数据丢失的间隙 数据
  • Xcode 异步单元测试在主线程上等待

    我正在尝试使用 Xcode 中的单元测试来测试一些异步代码 但主线程被阻塞 问题在于 某些正在测试的代码期望从 iOS 类 AVFoundation 接收回调 但是 AVFoundation 类似乎只会在主线程上回调 问题是 如果我正在进行
  • iphone sqlite 静态链接?

    有人静态链接 sqlite 而不是使用动态链接 吗 我遇到的问题是 越狱手机的用户没有与普通 iPhone 所采用的 sqlite 版本相同的版本 因此导致崩溃 我假设在我的应用程序中静态链接已知版本的 sqlite 就是答案 我需要全文支

随机推荐

  • scala 列表地图与mapConserve

    我试图理解mapConserve 据说 像xs map f 但如果函数f将所有元素映射到自身 则返回xs不变 来自List http www scala lang org api current index html scala colle
  • Java 8 - 无法在数组类型 Enum[] 上调用stream() [重复]

    这个问题在这里已经有答案了 为什么我无法调用stream 关于数组类型Enum DummyEnum array DummyEnum values array stream Compile Error ENUM public enum Dum
  • 如何使用 Java 获取我的电脑中可用串行端口的列表?

    我只是运行一些代码来获取计算机上的可用端口列表 当我有 3 个空闲的 com 端口时 它返回 false 我该如何解决这个问题 我的代码 public static void main String args SerialParameter
  • JavaScript 让 Firefox 开发者工具调试视图中的块作用域

    我正在调查该机构的工作情况let 块作用域在 JavaScript 中 特别是浏览器的调试视图如何显示信息 Using let在一个for循环创建一个块作用域 其中回调function timeoutHandler 可以访问 一切都很好 I
  • 格式化复数

    对于我的一个课程中的一个项目 我们必须输出最多五位小数的数字 输出可能是一个复数 而我无法弄清楚如何输出具有五位小数的复数 对于花车我知道它只是 print 0 5f variable name 复数有类似的东西吗 您可以使用如下所示的方法
  • 使用 Gradle 调用 powershell 脚本

    我是 Gradle 新手 所以请耐心等待 我只是想调用 ps1 文件来使用 gradle 执行 我将如何设置 build gradle 文件来执行同一目录中的 ps1 文件 提前致谢 你可以使用gradleExec https docs g
  • python in 和比较的运算符优先级

    以下比较产生True gt gt gt 1 in 11 True gt gt gt 1 in 11 True True 如果使用括号 我会得到一个 TypeError gt gt gt 1 in 11 True Traceback most
  • IBM Integration 总线 mqsicreatebar 及参考

    我对在我的环境中使用 mqsicreatebar 感到有点困惑 例如 我有以下文件结构 root Libraries Library1 Apps App1 project App1 是参考图书馆1 我想运行 mqsicreatebar 使其
  • 应用程序中的各个阶段在 Spark 中并行运行吗?

    我有一个疑问 阶段如何在 Spark 应用程序中执行 程序员可以定义的阶段执行是否具有一致性 或者是否由 Spark 引擎导出 检查这张图中的实体 阶段 分区 图片来源 http alvincjin blogspot in 2014 12
  • 显示宏选项

    在 Excel VBA 中 可以使用 MacroOptions 函数定义与宏或函数相关的一些信息 通过 VBA 输入后是否可以访问此类信息 谢谢 我已经搜索了一段时间但没有发现什么很棒的东西 我发现的唯一解决方法是使用 Chip Pears
  • 通过 URL 发布到 Reddit

    是否可以通过 URL 发布 Reddit 链接 例如对于 Facebook 你可以这样做 a href Share Stackoverflow on your profile a Reddit 是否有一个可以让我共享 URL 的等效端点 有
  • python 管道中的特征选择:如何确定特征名称?

    我使用 pipeline 和 grid search 选择最佳参数 然后使用这些参数来拟合最佳管道 best pipe 然而 由于 feature selection SelectKBest 处于管道中 因此尚未对 SelectKBest
  • 如何在 Android 上动态更新 ListView [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 在 Android 上 我怎样才能L
  • 在 C# 中实现生产者/消费者模式

    我该如何实施生产者 消费者C 中的模式使用活动和代表 使用这些设计模式时 在资源方面需要注意什么 有什么我需要注意的边缘情况吗 我知道这个线程有点老了 但由于我有时在搜索中遇到它 我决定为那些想知道如何实现简单的通用生产者 消费者作业队列的
  • VC++ 堆栈跟踪无法解析生产中的函数名称

    我最近使用实现了堆栈跟踪日志记录boost 的新 stacktrace 库 https www boost org doc libs develop doc html stacktrace getting started html int
  • 使用jquery下载文件自定义名称

    我正在使用 jQueryplugin https github com battatech battatech excelexport将 HTML 表导出到 Excel 使用chrome下载的文件名始终是download xls使用 moz
  • 如何使用 Thrust 计算 int2 数组的平均值

    我正在尝试计算包含点 x y 的某个数组的平均值 是否可以使用推力找到表示为 x y 点的平均点 我也可以将数组表示为thrust device vector
  • D3.js 结合条形图和折线图

    我想通过将条形图与折线图组合来创建多个系列图表 当我使用rangeBands 为了设置输出范围 该线从图表中第一个柱的开头开始绘制 并在最后一个柱的开头结束 我应该更改什么以使该线从第一个刻度线开始并在最后一个刻度线结束 var data
  • 使用模拟器进行条码扫描的 Windows Mobile 应用程序

    我想为 Motorolo MC 9190 G 手机开发简单的应用程序 它有内置的条形码扫描仪 我想扫描条形码并将其显示在消息框中 我没有手机 所以我必须在模拟器中测试它 当我在模拟器中部署代码时 它给出了 null 异常错误 我的代码是 我
  • 如何对ServiceStack进行单元测试?

    我喜欢 SS 但我在尝试对我的业务层进行单元测试时摸不着头脑 我是单元测试和模拟的新手 并且一直在阅读 NSubstitute 因为这看起来像是一个有趣的模拟层 我的文件结构大致如下 MainAppHostProject AppStart