2

나는 지속성 성 액티브를 사용하고, 나는 다음 할 것입니다 내 지속성 테스트를위한 기본 클래스 작성하려고 해요 : 각 테스트 케이스에 대한NHibernate 세션을 플러시하고 트랜잭션을 커밋하지 않고 새 세션을 가져올 수 있습니까?

  • 열기 거래를하고 다시 그것을 롤 결국 테스트 케이스의 끝 부분을 제거해야하므로 각 테스트 케이스별로 스키마를 다시 만들지 않고도 각 테스트 케이스에 대해 깨끗한 DB를 얻을 수있다.
  • 내 NHibernate 세션을 비우고 테스트 도중 새 NHibernate 세션을 가져 오는 기능을 제공합니다. 따라서 지속성 작업이 NHibernate 세션이 아닌 DB에 실제로 도달했음을 알 수 있습니다.

내 기본 클래스 (ARTestBase)가 작동하고 있음을 증명하기 위해 다음 샘플 테스트를 준비했습니다.

[TestFixture] 
public class ARTestBaseTest : ARTestBase 
{ 
    [Test] 
    public void object_created_in_this_test_should_not_get_committed_to_db() 
    { 
     ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"}); 

     Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1)); 
    } 

    [Test] 
    public void object_created_in_previous_test_should_not_have_been_committed_to_db() 
    { 
     ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"}); 

     Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1)); 
    } 

    [Test] 
    public void calling_flush_should_make_nhibernate_retrieve_fresh_objects() 
    { 
     var savedEntity = new Entity {Name = "test"}; 
     ActiveRecordMediator<Entity>.Save(savedEntity); 
     Flush(); 
     // Could use FindOne, but then this test would fail if the transactions aren't being rolled back 
     foreach (var entity in ActiveRecordMediator<Entity>.FindAll()) 
     { 
      Assert.That(entity, Is.Not.SameAs(savedEntity)); 
     } 
    } 
} 

여기는 기본 클래스에서 최선의 노력입니다. 정확하게 Flush()을 구현하므로 세 번째 테스트 케이스가 통과합니다. 그러나 트랜잭션을 롤백하지 않으므로 두 번째 테스트가 실패합니다.

public class ARTestBase 
{ 
    private SessionScope sessionScope; 
    private TransactionScope transactionScope; 

    [TestFixtureSetUp] 
    public void InitialiseAR() 
    { 
     ActiveRecordStarter.ResetInitializationFlag(); 
     ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance); 
     ActiveRecordStarter.CreateSchema(); 
    } 

    [SetUp] 
    public virtual void SetUp() 
    { 
     transactionScope = new TransactionScope(OnDispose.Rollback); 
     sessionScope = new SessionScope(); 
    } 

    [TearDown] 
    public virtual void TearDown() 
    { 
     sessionScope.Dispose(); 
     transactionScope.Dispose(); 
    } 

    protected void Flush() 
    { 
     sessionScope.Dispose(); 
     sessionScope = new SessionScope(); 
    } 

    [TestFixtureTearDown] 
    public virtual void TestFixtureTearDown() 
    { 
     SQLiteProvider.ExplicitlyDestroyConnection(); 
    } 
} 

메모리 내장 데이터베이스가있는 사용자 지정 SQLite 공급자를 사용하고 있습니다. 내 사용자 지정 공급자 (this blog post에서 가져옴)는 스키마를 유지 관리하기 위해 항상 연결을 유지합니다. 이 제거하고 일반 SQL Server 데이터베이스를 사용하여 동작을 변경하지 마십시오.

필요한 동작을 수행 할 수있는 방법이 있습니까?

답변

1

ActiveRecord에 대해서는 확신 할 수 없지만, NHibernate에서는 트랜잭션이 세션에 속하며, 다른 라운드에는 속하지 않습니다.

ADO.Net을 많이 사용 해본 적이 있다면 IDbTransaction을 만들면 연결이 필요합니다. ActiveRecord의 TransactionScope (및 NHibnerate의 ITransaction)은 본질적으로 IDbTransaction이므로, TransactionScope 앞에 SessionScope을 만들어야합니다.

당신은 또한 (당신이 NHibernate에 1.2 GA 또는 NHibernate에 2 *를 사용하는 경우에 따라, 어떤 FlushMode 당신의 SessionScope가있다)를 찾을 수 있습니다 FindAll()에 전화가 NHibernate에로, 세션 어쨌든 플러시가 발생할 수 있음을 무엇 것이다 Save에 대한 마지막 호출을 수행하지 않고 올바른 데이터를 검색 할 수 없다는 것을 깨달으십시오.

이 모든 것이 완료되었습니다. SessionScope을 새로 만드는 대신 SessionScope.Flush()을 사용해 보았습니까?

0

SessionScope.Flush()을 사용하면 세 번째 테스트가 실패합니다. 내가 이해할 때 Flush()은 SQL을 실행하여 내 레코드를 DB로 푸시하지만 세션에서 오브젝트를 축출하지는 않습니다. 당신이 말하는 플러시를 일으키는 FindAll()에 맞는 말입니다.

정말 원하는 것은 SessionScope.Flush() (세션 상태와 DB의 상태를 동기화) + SessionScope.EvictAll() (후속 쿼리에서 새 개체를 확보하기 위해)입니다. 내 new SessionScope()EvictAll()을 (를) 시뮬레이션하려는 시도였습니다.

다른 방법보다는 트랜잭션을 둘러싸고있는 세션에 대한 의견은 나에게 아이디어를 제공했습니다.나는 그것이 플러시 SessionScope 내부 TransactionScope 안에 새로운 SessionScope을 만들고,이 거래에 참여를 기대하는 것이 얼마나 정결 확실하지 않다, 그러나 작동하는 것 같다 : 더 생각에

public abstract class ARTestBase 
{ 
    private SessionScope sessionScope; 
    private TransactionScope transactionScope; 
    private bool reverse; 
    private IList<SessionScope> undisposedScopes; 

    [TestFixtureSetUp] 
    public void InitialiseAR() 
    { 
     ActiveRecordStarter.ResetInitializationFlag(); 
     ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance); 
     ActiveRecordStarter.CreateSchema(); 
     InitialiseIoC(); 
     undisposedScopes = new List<SessionScope>(); 
    } 

    [SetUp] 
    public virtual void SetUp() 
    { 
     sessionScope = new SessionScope(); 
     transactionScope = new TransactionScope(OnDispose.Rollback); 
     transactionScope.VoteRollBack(); 
     base.CreateInstanceUnderTest(); 
     reverse = false; 
    } 

    [TearDown] 
    public virtual void TearDown() 
    { 
     if (reverse) 
     { 
      sessionScope.Dispose(); 
      transactionScope.Dispose(); 
     } 
     else 
     { 
      transactionScope.Dispose(); 
      sessionScope.Dispose(); 
     } 
    } 

    [TestFixtureTearDown] 
    public virtual void TestFixtureTearDown() 
    { 
     foreach (var scope in undisposedScopes) 
     { 
      scope.Dispose(); 
     } 
     SQLiteProvider.ExplicitlyDestroyConnection(); 
    } 

    protected void Flush() 
    { 
     reverse = true; 
     sessionScope.Flush(); 
     undisposedScopes.Add(sessionScope); 
     sessionScope = new SessionScope(); 
    } 
} 

이 원 각 테스트 케이스에서 두 번 이상 플러시 할 수 없습니다. 나는 스코프를 더 조심스럽게 추적함으로써이를 처리 할 수 ​​있다고 생각합니다. 나는 나중에 그것을 들여다 볼지도 모른다.

관련 문제