帮助我测试与NHibernate和NUnit的一对多关系

时间:2009-08-20 15:51:50

标签: c# nhibernate nunit

我有一个类,Task,它有一个属性TaskLibrary,它将加载并运行一些代码。因此,任何任务都有一个库,但任何库都可以有很多任务。我的问题是我的确保任务的Library属性不为null的测试失败(所以它可能只是我的测试)。我的课程实际上是这样的:

public class Task
{
  public virtual int TaskId {get;set;}
  public virtual string Locked {get;set;}
  public virtual int Status {get;set;}
  public virtual TaskLibrary Library {get;set;}
}

public class TaskLibrary
{
  public virtual int LibraryId {get;set}
  public virtual string Name {get;set;}
  public virtual string Description {get;set;}
  public virtual byte[] Dll {get;set}
  public virtual IEnumerable<Task> Tasks {get;set;}
}

我的NHibernate映射看起来像这样:

  <class name="Task">
    <id name="Id" column="TaskId" type="Int32" unsaved-value="-1">
      <generator class="identity"/>
    </id>
    <property name="Locked" column="Locked"/>
    <property name="Status" column="Status"/>
    <many-to-one name="Library" class="TaskLibrary" fetch="join"/>
  </class>
  <class name="TaskLibrary">
    <id name="Id" column="LibraryId">
      <generator class="identity"/>
    </id>
    <property name="Name"/>
    <property name="Description"/>
    <property name="Dll"/>
    <set name="Tasks" lazy="true">
      <key column="LibraryId"/>
      <one-to-many class="Task"/>
    </set>
  </class>

我的测试类看起来像这样:

[TestFixture]
public class TaskRepositoryFixture
{
    private ISessionFactory _sessionFactory;
    private Configuration _configuration;

    private readonly Task[] _tasks = new[]
        {
            new Task {Id = 1, Status = 1, Locked = 0, Library = new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
            new Task {Id = 2, Status = 1, Locked = 0, Library = new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
            new Task {Id = 3, Status = 1, Locked = 0, Library = new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
            new Task {Id = 4, Status = 1, Locked = 0, Library = new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
            new Task {Id = 5, Status = 1, Locked = 0, Library = new TaskLibrary { Id =3, Description = "Test Library 3", Name = "Tast3.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
        };

    private readonly TaskLibrary[] _libraries = new[]
        {
            new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")},
            new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")},
            new TaskLibrary { Id =3, Description = "Test Library 3", Name = "Tast3.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")}
        };

    private void CreateInitialData()
    {
        using (ISession session = _sessionFactory.OpenSession())
        using (ITransaction transaction = session.BeginTransaction())
        {
            foreach (var lib in _libraries)
                session.Save(lib);

            foreach (var task in _tasks)
                session.Save(task);

            transaction.Commit();
        }
    }


    [TestFixtureSetUp]
    public void TestFixtureSetUp()
    {
        _configuration = new Configuration();
        _configuration.Configure();
        _configuration.AddAssembly("DistPollAutoTasksShared");
        _sessionFactory = _configuration.BuildSessionFactory();
    }

    [SetUp]
    public void SetupContext()
    {
        new SchemaExport(_configuration).Execute(false, true, false, false);
        CreateInitialData();
    }

    [Test]
    public void CanGetLibraryFromTask()
    {
        ITaskRepository repository = new TaskRepository();
        var fromDb = repository.GetById(_tasks[0].Id);
        Assert.IsNotNull(fromDb.Library);
        Assert.IsNotNull(fromDb.Library.Dll);
    }
  }

并且,MSSQL2000数据库中的Tasks表是:

CREATE TABLE [dbo].[Tasks](
    [TaskId] [int] IDENTITY(1,1) NOT NULL,
    [TaskLibrary] [int] NOT NULL,
    [Status] [int] NOT NULL,
    [Locked] [int] NOT NULL
)

如果你还和我在一起......

从我的Task类中,我只想要一个Library属性的TaskLibrary类的实例。此外,如果我正在使用库本身,我希望能够使用该库懒惰地检索所有任务的IEnumerable。但是,当我运行测试时,我收到此错误:

TestCase 'DistPollAutoTasksShared.Tests.TaskRepositoryFixture.CanGetLibraryFromTask'
failed: NHibernate.LazyInitializationException : Could not initialize proxy - no Session.
    at NHibernate.Proxy.AbstractLazyInitializer.Initialize()
    at NHibernate.Proxy.AbstractLazyInitializer.GetImplementation()
    at NHibernate.Proxy.Poco.Castle.CastleLazyInitializer.Intercept(IInvocation invocation)
    at Castle.DynamicProxy.AbstractInvocation.Proceed()
    at TaskLibraryProxy2bd44073e90f47298039abfbfda11492.get_Dll()

这是我第一次使用NHibernate,所以我还在学习。我真的想要获得基础知识的良好基础,所以我一直坚持到这里。任何帮助,建议,阅读材料(我已阅读所有this question's建议和其他一些)将不胜感激。

修改

更改fetch =“join”后,我从Task类中获得了我想要的功能。但是,我为TaskLibrary类的Tasks属性添加了另一个测试:

    [Test]
    public void CanGetTasksByLibrary()
    {
        ITaskLibraryRepository repository = new TaskLibraryRepository();
        var fromDb = repository.GetById(_libraries[0].Id).Tasks;

        Assert.IsNotNull(fromDb);
        Assert.True(fromDb.Count() == 2, "Cannot get IEnumerable<Task> from TaskLibrary");
    }

但是,断言失败并出现此错误(我已更新上面的代码以反映我所做的任何更改):

TestCase 'DistPollAutoTasksShared.Tests.TaskLibraryRepositoryFixture.CanGetTasksByLibrary'
failed: 
  Cannot get IEnumerable<Tasks> from TaskLibrary
  Expected: True
  But was:  False

3 个答案:

答案 0 :(得分:1)

<many-to-one name="Library" class="TaskLibrary" fetch="join" />

这将在每个选择中加入图书馆。

<many-to-one name="Library" class="TaskLibrary" lazy="false" />

这将急切地为库执行单独的选择。

否则,如果只设置fetch =“select”(这是默认值),它将延迟加载库。

http://ayende.com/Blog/archive/2009/04/09/nhibernate-mapping-ltmany-to-onegt.aspx

http://nhibernate.info/doc/nh/en/index.html#collections-lazy

答案 1 :(得分:0)

答案 2 :(得分:0)

不要更改测试的映射,您的需求应该驱动对象的映射方式。 您的存储库方法在从数据库获取后关闭会话。您需要为整个测试方法保持会话打开。   要弄清楚如何做到这一点,您需要告诉我们您如何管理会话。这些是绑定到事务/ threadlocal吗?