单元测试服务层 - NUnit、NHibernate

发布于 2024-08-26 01:11:28 字数 460 浏览 4 评论 0原文

我想对依赖服务层进行单元测试,它允许我执行 CRUD 操作,而无需使用 NUnit 进行模拟。我知道这可能是不好的做法,但无论如何我想尝试一下 - 即使测试必须整夜运行。我的数据是使用 NHibernate 保存的,并且我已经实现了一个小库来“引导”数据库,我可以在 [Setup] 方法中使用它。我只是想知道是否有人做过类似的事情以及引导数据库最快的方法是什么。我正在使用这样的东西:

var cfg = new Configuration();
            cfg.Configure();
            cfg.AddAssembly("Bla");
            new SchemaExport(cfg).Execute(false, true, false);

建立数据库模式。之后,我从一些 Excel 表中填充一些查找表。

任何反馈将不胜感激。谢谢。

基督教

I would like to unit test a DEPENDENT service layer which allows me to perform CRUD operation without mocking using NUnit. I know this is probably bad practice but I want to give it a try anyway - even if the tests have to run over night. My data is persisted using NHibernate and I have implemented a little library that 'bootstraps' the database which I could use in a [Setup] method. I am just wondering if someone has done something similar and what the fastest method for bootstrapping the database is. I am using something like this:

var cfg = new Configuration();
            cfg.Configure();
            cfg.AddAssembly("Bla");
            new SchemaExport(cfg).Execute(false, true, false);

to establish the db schema. After that I populate some lookup tables from some Excel tables.

Any feedback would be very much appreciated. Thanks.

Christian

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

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

发布评论

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

评论(2

彡翼 2024-09-02 01:11:28

Ayende 在这篇 博客文章中提供了这种方法的一个很好的例子。他的例子和我的评论如下所示。

由于创建配置的成本很高,因此每次测试运行仅创建一次。使用 SQLite 内存数据库,因为这是执行查询的最快方法。

public class InMemoryDatabaseTest : IDisposable
{
    private static Configuration Configuration;
    private static ISessionFactory SessionFactory;
    protected ISession session;

    public InMemoryDatabaseTest(Assembly assemblyContainingMapping)
    {
        if (Configuration == null)
        {
            Configuration = new Configuration()
                .SetProperty(Environment.ReleaseConnections,"on_close")
                .SetProperty(Environment.Dialect, typeof (SQLiteDialect).AssemblyQualifiedName)
                .SetProperty(Environment.ConnectionDriver, typeof(SQLite20Driver).AssemblyQualifiedName)
                .SetProperty(Environment.ConnectionString, "data source=:memory:")
                .SetProperty(Environment.ProxyFactoryFactoryClass, typeof (ProxyFactoryFactory).AssemblyQualifiedName)
                .AddAssembly(assemblyContainingMapping);

            SessionFactory = Configuration.BuildSessionFactory();
        }

        session = SessionFactory.OpenSession();

        new SchemaExport(Configuration).Execute(true, true, false, true, session.Connection, Console.Out);
    }

    public void Dispose()
    {
        session.Dispose();
    }
}

使用此功能时,每个测试都从创建所需的数据开始。

public class BlogTestFixture : InMemoryDatabaseTest
{
    public BlogTestFixture() : base(typeof(Blog).Assembly)
    {
    }

    [Fact]
    public void CanSaveAndLoadBlog()
    {
        object id;

        using (var tx = session.BeginTransaction())
        {
            id = session.Save(new Blog
            {
                AllowsComments = true,
                CreatedAt = new DateTime(2000,1,1),
                Subtitle = "Hello",
                Title = "World",
            });

            tx.Commit();
        }

        session.Clear();


        using (var tx = session.BeginTransaction())
        {
            var blog = session.Get<Blog>(id);

            Assert.Equal(new DateTime(2000, 1, 1), blog.CreatedAt);
            Assert.Equal("Hello", blog.Subtitle);
            Assert.Equal("World", blog.Title);
            Assert.True(blog.AllowsComments);

            tx.Commit();
        }
    }
}

Ayende has a good example of this approach in this blog post. His example is shown below with my comments.

As the Configuration is expensive to create, it is created only once per test run. A SQLite in-memory database is used as this is the fastest way to do queries.

public class InMemoryDatabaseTest : IDisposable
{
    private static Configuration Configuration;
    private static ISessionFactory SessionFactory;
    protected ISession session;

    public InMemoryDatabaseTest(Assembly assemblyContainingMapping)
    {
        if (Configuration == null)
        {
            Configuration = new Configuration()
                .SetProperty(Environment.ReleaseConnections,"on_close")
                .SetProperty(Environment.Dialect, typeof (SQLiteDialect).AssemblyQualifiedName)
                .SetProperty(Environment.ConnectionDriver, typeof(SQLite20Driver).AssemblyQualifiedName)
                .SetProperty(Environment.ConnectionString, "data source=:memory:")
                .SetProperty(Environment.ProxyFactoryFactoryClass, typeof (ProxyFactoryFactory).AssemblyQualifiedName)
                .AddAssembly(assemblyContainingMapping);

            SessionFactory = Configuration.BuildSessionFactory();
        }

        session = SessionFactory.OpenSession();

        new SchemaExport(Configuration).Execute(true, true, false, true, session.Connection, Console.Out);
    }

    public void Dispose()
    {
        session.Dispose();
    }
}

When using this, each test starts by creating required data.

public class BlogTestFixture : InMemoryDatabaseTest
{
    public BlogTestFixture() : base(typeof(Blog).Assembly)
    {
    }

    [Fact]
    public void CanSaveAndLoadBlog()
    {
        object id;

        using (var tx = session.BeginTransaction())
        {
            id = session.Save(new Blog
            {
                AllowsComments = true,
                CreatedAt = new DateTime(2000,1,1),
                Subtitle = "Hello",
                Title = "World",
            });

            tx.Commit();
        }

        session.Clear();


        using (var tx = session.BeginTransaction())
        {
            var blog = session.Get<Blog>(id);

            Assert.Equal(new DateTime(2000, 1, 1), blog.CreatedAt);
            Assert.Equal("Hello", blog.Subtitle);
            Assert.Equal("World", blog.Title);
            Assert.True(blog.AllowsComments);

            tx.Commit();
        }
    }
}
不一样的天空 2024-09-02 01:11:28

在编写此类集成测试时,要记住的最重要的事情是您仍然应该

  • 尽可能自动化(最好是一切),其中包括设置数据库和删除使用后再次
  • 避免 General Fixture 反模式,这意味着每个测试用例应该以空数据库,并且本身使用后门操纵填充适当的行。

我写过我自己的数据库测试经验 过去有过几次。

When writing such Integration Tests, the most important things to keep in mind that you should still

  • automate as much as possible (preferrably everything), which includes setting up the database and deleting it again after use
  • avoid the General Fixture antipattern, which means that each test case should start with an empty database, and itself fill in appropriate rows using Back Door Manipulation.

I have written about my own experiences with testing against databases several times in the past.

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