简体   繁体   中英

Help me test a one-to-many realtionship with NHibernate and NUnit

I have a class, Task, and it has a property TaskLibrary which is dll it will load and run some code from. So, any task has one library, but any library can have many tasks. My problem is that my test for making sure the task's Library property is not null is failing (so it could just be my test). My classes are effectively this:

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;}
}

My NHibernate mappings look like this:

  <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>

My test class looks like this:

[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);
    }
  }

And, the Tasks table in the MSSQL2000 database is this:

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

If you're still with me...

From my Task class, I just want an instance of the TaskLibrary class for the Library property. Also, if I'm working with the libraries themselves, I want to be able to lazily retrieve an IEnumerable of all tasks using that library. However, when I run the test, I get this error:

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()

This is the first time I've used NHibernate, so I'm still learning. I really want to get a good foundation of the basics, so I'm stuck here until then. Any help, suggestions, reading material (I've read all of this question's suggestions and some others) would be appreciated.

EDIT:

After changing fetch="join", I'm getting the functionality I want from the Task class. However, I've added another test for the Tasks property of the TaskLibrary class:

    [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");
    }

But, an assertion fails with this error (I've updated the code above to reflect any changes I've made):

TestCase 'DistPollAutoTasksShared.Tests.TaskLibraryRepositoryFixture.CanGetTasksByLibrary'
failed: 
  Cannot get IEnumerable<Tasks> from TaskLibrary
  Expected: True
  But was:  False
<many-to-one name="Library" class="TaskLibrary" fetch="join" />

This would join the Library on every select.

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

This will eagerly execute separate select for the Library.

Otherwise, it will lazy load the Library if you only set fetch="select" (which is the default).

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

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

Dont change the mapping for the test , your requirements should drive how objects are mapped . Your repository method is closing the session after fetching fromDB. You need to keep the session open for the whole test method. To figure out how to do that you need to tell us how you are managing your session . Are those tied to a transaction / threadlocal ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM