.net 与 nhibernate 的集成测试

发布于 2024-10-01 10:36:57 字数 931 浏览 2 评论 0原文

我一直在为我的最新项目做一些诚实的 TDD,并且很喜欢它,之前做过单元测试,但不是认真的 TDD,我发现它很有帮助。

我的项目的一些背景:

  • ASP.Net 前端 -
  • NHibernate 用于与 SQL Server 2008 Express 进行数据库交互 -
  • 用于域逻辑和单元测试的 C# 4.0 DLL,在 NUnit 中完成并通过 resharper 运行。
  • 运行 NAnt 构建脚本的 Teamcity CI 服务器。

我现在处于某种“alpha”版本中,发现所有错误都是集成错误,主要是因为我的集成测试是手动使用该站点,以及一些小的自动化内容(我已停止运行)。考虑到我对测试套件的严格培养,这是相当糟糕的,我想纠正它。

我的问题是,进行集成测试的最佳方法是什么,或者有什么文章我可以阅读。我知道在 ASP.NET Webforms 中测试 UI 将是一件痛苦的事情(将来会转向更可测试的框架,但一次一步)。但我想确保我与 hibernate 的交互经过正确测试。

因此,我需要一些与 Nhibernate 相关的集成测试

  • (缓存、会话等)的提示 -
  • 测试数据,我发现“NDBUnit”是我应该考虑用来使数据处于良好状态的东西?与 NHibernate 兼容吗?
  • 我应该将数据库换成 SQLite 还是其他什么?或者只是设置另一个仅保存测试数据的 SQL Server 数据库?
  • 我怎样才能使这些测试可维护?我进行了一些集成测试,但它们给我带来了麻烦,并发现自己在避免它们。我想这主要是因为我每次都没有设置一致的状态。

只是一些一般性的建议也很好,我已经阅读了 Kent Beck 的 TDD 示例和 Roy Osherove 的《单元测试的艺术》,它们对于单元测试/tdd 非常有用,但我很想阅读更多有关集成测试的内容,编写它们的策略(你应该测试什么等)---

I've been doing some honest-to-God-TDD for my latest project, and am loving it, having previously done unit testing but not serious TDD I'm finding it helpful.

Some background on my project:

  • ASP.Net Front End-
  • NHibernate for database interaction with SQL Server 2008 express-
  • C# 4.0 DLL's for DOmain Logic and Unit Tests which are done in NUnit and ran through resharper.
  • Teamcity CI server running a NAnt build script.

I'm in a sort of 'alpha' release now, and am finding all the bugs are integration bugs, mainly as my integration testing has been manual use of the site, and some minor automated stuff (which I've stopped running). This is pretty poor given how strictly I've nurtured my test suite and I want to rectify it.

My question is, what is the best way to do integration tests, or is there any articles I can read. I understand that testing the UI is going to be a pain in ASP.NET Webforms (will move to a more testable framework in future, but one step at a time). But I want to make sure my interactions with hibernate are tested correctly.

So I need some tips on integration testing in relation to

  • Nhibernate (caching, sessions etc)-
  • Test data, I've found 'NDBUnit' is that what i should be looking at using to get my data in a good state? Is that compatible with NHibernate?
  • Should I swap the database out for SQLite or something? Or just setup another SQL server DB which holds test data only?
  • How can I make these tests maintainable? I had a few integration tests but they caused me hassles and found myself avoiding them. I think this was mainly due to me not setting a consistent state each time.

Just some general advice too would be great, I've read TDD by example by Kent Beck and The Art of Unit Testing by Roy Osherove and they were great for unit testing /tdd but I would love to read a little more about integration tests and strategies for writing them (what you should test etc) ---

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

行至春深 2024-10-08 10:36:57

关于数据库部分:
- 您可以直接按照本文的内容使用它:使用内置 NHibernate 支持进行单元测试
- 使用 SQLite 来加速测试也非常有用。只是在这种情况下,您应该意识到您不再真正针对实际的生产配置。
- SQLite 并不支持 SQL Server 所支持的所有功能。 本文显示了必要的代码示例切换到 SQLite 的测试设置 - 它非常简单明了。
- NDbUnit 作为准备测试数据的机制也是一个不错的选择 - 只要您不希望在数据库上频繁更改架构(在这种情况下,维护所有相关的 xml 会变得相当多的工作)文件...)。
关于 ASP.NET 部分:
- 您可能会发现像 Selenium 这样的工具对于 UI 驱动的测试很有帮助。

呵呵!
托马斯

Concerning the Database part:
- You may use it directly along the lines of this article: Unit testing with built-in NHibernate support.
- Using SQLite to speed up the tests can also be very useful. Only that in this case you should be aware that you're not really targeting the real production configuration anymore.
- SQLite does not support all features that SQL Server does. This article shows a code sample for the necessary test setup to switch to SQLite - it's quite easy and straightforward.
- NDbUnit as a mechanism to have the test data prepared is also a good choice - as long as you don't expect to have frequent schema changes on your Db (in this case it becomes quite a lot of work to maintain all the related xml files...).
Concerning the ASP.NET part:
- You may find a tool like Selenium helpful for UI-driven tests.

HTH!
Thomas

盗琴音 2024-10-08 10:36:57

参加聚会有点晚了,但这就是我已经做了一段时间的事情了。

我正在编写 REST API,它们将由我们的移动应用程序使用。移动应用程序也是用 C# 编写的,因此编写 API 包装器 (SDK) 对我来说很有意义。

在集成测试时,我设置了测试用例,使用 SDK 来测试 API 的所有端点。运行测试时,API 在我的本地 IIS 上以开发模式运行。每次服务器启动时,我的开发数据库都会被擦除、重新创建,并为所有表添加数据,这给了我一个有点现实的场景。我也不必担心测试更新/删除,因为只需重建服务器项目,NHibernate 将删除、创建和播种我的数据库。如果需要,可以根据每个请求进行更改。

在测试我的存储库时,了解 NHibernate 是否可以翻译我的查询对我来说非常重要,因此我的所有存储库测试都使用 LocalDB,它是为每个测试用例重新创建的。这意味着每个测试用例都可以设置查询测试成功所需的种子数据。

另一件事是,当用实际数据播种数据库时,您还可以免费测试外键设置。另外,播种器正在使用您的域类,因此它看起来也不错!

播种器的示例:

public void Seed(ISession s) 
{
  using(var tx = s.BeginTransaction() 
  {
    var account1 = new Account { FirstName = "Bob", LastName = "Smith" };
    var account2 = new Account { FirstName = "John", LastName = "Doe" };
    account1.AddFriend(account2); // manipulates a friends collection
    s.Save(account1);
  }
}

您应该在创建会话工厂时调用播种器。

重要提示:此设置是通过 IoC 容器完成的。

A bit late to the party, but this is what I've been doing for a while.

I am writing REST API's, which are to be consumed by our mobile apps. The mobile apps are also written in C#, so it makes sense for me to write an API wrapper (SDK).

When integration testing, I set up test cases that tests all endpoints of the API, using the SDK. When running the tests, the API is running on my local IIS, in development mode. Everytime the server is started, my dev database is wiped, recreated, and seeded with data for all tables, giving me a somewhat realistic scenario. I also don't have to worry about testing updates/deletes, because all it takes is a rebuild of the server project, and NHibernate will drop, create and seed my database. This could be changed to every request if desired.

When testing my repositories, it's important for me to know if my queries are translateable by NHibernate, so all my repository tests are using LocalDB, which is recreated for every single test case. That means every test case can set up the required seed data for the query tests to succeed.

Another thing, when seeding your database with realistic data, you are also getting your foreign-key setups tested for free. Also, the seeder is using your domain classes, so it look's good, too!

An example of a seeder:

public void Seed(ISession s) 
{
  using(var tx = s.BeginTransaction() 
  {
    var account1 = new Account { FirstName = "Bob", LastName = "Smith" };
    var account2 = new Account { FirstName = "John", LastName = "Doe" };
    account1.AddFriend(account2); // manipulates a friends collection
    s.Save(account1);
  }
}

You should call the seeder when creating your session factory.

Important: setting this up is done with an IoC container.

牵强ㄟ 2024-10-08 10:36:57

简短的答案是:不进行集成测试。

我们有以下设置:

  • 我们的单元测试尽可能少地进行测试。我们只测试业务代码的一个功能(不是直接的方法,而是更多的逻辑功能);

  • 为业务代码的每个功能编写单元测试;

  • 为业务代码的不同功能之间的交互编写单元测试;

  • 确保这些测试涵盖所有内容。

这将为您提供一组涵盖所有内容的单元测试。

我们确实有集成测试,但这些测试都是写在 Word 文档中的,而且通常只是原始规范。质量检查人员在代码交付时运行这些,并且大多数时候它都能正常工作,因为我们已经测试了每一个小部分。

InfoQ 上有一个很棒的演示,很好地解释了这种工作方式:集成测试是一个骗局。

关于测试 NHibernate 的一件事。我们应用了存储库模式。这样做的目的是让我们的 NHibernate 查询变得非常非常简单,例如:

public class NhRepository<T> : IRepository<T>
{
    public T Get(int id)
    {
        return GetSession().Get<T>(id);
    }
}

public interface IUserRepository : IRepository<User>
{
    IEnumerable<User> GetActiveUsers();
}

public class UserRepository : NhRepository<User>, IUserRepository
{
    public IEnumerable<User> GetActiveUsers()
    {
        return
            from user in GetSession().Users
            where user.IsActive
            return user;
    }
}

Windsor 结合使用IoC容器提供我们的数据访问。这种设置的问题是:

  1. 查询非常简单(无论如何,其中 98% 都是这样),而且我们没有彻底测试它们。这可能听起来很奇怪,但与任何其他机制相比,我们更倾向于使用同行评审来测试这些;

  2. 这些存储库很容易被嘲笑。这意味着对于上面的存储库,我们有一个模拟可以执行以下操作:

    varrepositoryMock=mocks.StrictMock();
    
    var activeUsers = new List<用户>();
    
    for (int i = 0; i < 10; i++)
    {
        var user = UserMocks.CreateUser();
        用户.IsActive = true;
        activeUsers.Add(用户);
    }
    
    Expect.Call(repositoryMock.GetActiveUsers()).Return(activeUsers);
    

    实际的代码要简洁得多,但你明白了。

The short answer is: don't do integration tests.

We have the following setup:

  • Our unit tests test as little as possible. We only test one function of the business code (not directly a method, but more a logical piece of functionality);

  • Write a unit test for every function of your business code;

  • Write a unit test for interaction between different functions of your business code;

  • Make sure these tests cover everything.

This will give you a set of unit tests that cover everything.

We do have integration tests, but these are written up in Word documents and are often just the original specs. A QA person runs these when the code is delivered and most of the times it just works, because we've already tested every little piece.

On InfoQ, there is a terrific presentation which explains this way of working very well: Integration Tests Are a Scam.

One thing about testing NHibernate. We have applied the repository pattern. What this does is that our NHibernate queries become very very simple, like:

public class NhRepository<T> : IRepository<T>
{
    public T Get(int id)
    {
        return GetSession().Get<T>(id);
    }
}

public interface IUserRepository : IRepository<User>
{
    IEnumerable<User> GetActiveUsers();
}

public class UserRepository : NhRepository<User>, IUserRepository
{
    public IEnumerable<User> GetActiveUsers()
    {
        return
            from user in GetSession().Users
            where user.IsActive
            return user;
    }
}

This in combination with the Windsor IoC container provides our data access. The thing with this setup is that:

  1. The queries are incredibly simple (98% of them anyway) and we don't test them thoroughly. That may sound strange, but we tend to test these more using peer review than any other mechanism;

  2. These repositories can be easily mocked. This means that for the above repository, we have a mock that does something like this:

    var repositoryMock = mocks.StrictMock<IUserRepository>();
    
    var activeUsers = new List<User>();
    
    for (int i = 0; i < 10; i++)
    {
        var user = UserMocks.CreateUser();
        user.IsActive = true;
        activeUsers.Add(user);
    }
    
    Expect.Call(repositoryMock.GetActiveUsers()).Return(activeUsers);
    

    The actual code is a lot more concise, but you get the idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文