|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Nested TransactionScopeI am trying to set up some nested transactions to speed up a group of unit tests. The unit tests call a common method to build up some test data, which takes about 30 seconds and then runs a specific test. Each C# unit tests has a using statement that creates a new new TransactionScope(TransactionScopeOption.Required, timeSpan) (timeSpan is 600 seconds). Data access uses the Patterns and Practices Enterprise Library 2.0 against a SQL Server 2005 database. It all works fine but I would like to speed up my total test time and only create the test data once. I added [ClassInitialize()] and [ClassCleanup()] methods to run when my unit tests start and end. In the ClassInitialize method I created a TransactionScope(TransactionScopeOption.Required, timeSpan) and in the ClassCleanup I added a transactionScope.Dispose(); In each test, I created a TranactionScop(TransactionScopeOption.RequiresNew, timeSpan) both with a duration of 5 minutes. Now I am getting a timeout error. "Error retrieving data for the query from command with CommandText of xxx: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding." (where xxx is a select stored procedure name) If I replace RequiresNew with Required in the individual tests, the first test works and subsequent tests fail, which makes sense because it appears to join and roll back the outer ambient transaction. Does anyone know why nesting I would get the timeout at about 30 seconds with the RequiresNew? Thanks, David Morris David Morris wrote:
Show quote > Hello, I don't see where you're nesting transactions: nested transactions are> > I am trying to set up some nested transactions to speed up a group of > unit tests. The unit tests call a common method to build up some test > data, which takes about 30 seconds and then runs a specific test. > Each C# unit tests has a using statement that creates a new new > TransactionScope(TransactionScopeOption.Required, timeSpan) (timeSpan > is 600 seconds). Data access uses the Patterns and Practices > Enterprise Library 2.0 against a SQL Server 2005 database. > > It all works fine but I would like to speed up my total test time and > only create the test data once. I added [ClassInitialize()] and > [ClassCleanup()] methods to run when my unit tests start and end. In > the ClassInitialize method I created a > TransactionScope(TransactionScopeOption.Required, timeSpan) and in > the ClassCleanup I added a transactionScope.Dispose(); In each test, > I created a TranactionScop(TransactionScopeOption.RequiresNew, > timeSpan) both with a duration of 5 minutes. Now I am getting a > timeout error. > > "Error retrieving data for the query from command with CommandText of > xxx: Timeout expired. The timeout period elapsed prior to > completion of the operation or the server is not responding." (where > xxx is a select stored procedure name) > > If I replace RequiresNew with Required in the individual tests, the > first test works and subsequent tests fail, which makes sense because > it appears to join and roll back the outer ambient transaction. > > Does anyone know why nesting I would get the timeout at about 30 > seconds with the RequiresNew? done using nested using statements. For example: it's not said that the start/end methods of the test fixture are ran in the same thread/appdomain and neither is it defined in which order the tests are ran. Unit tests should be atomic, thus shouldn't rely on order. If you need test-data for your tests, I'd store it in a second schema in your db and copy it over inside your db to your schema targeted by the tests, either with a proc or with a sql statement. FB -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------ Frans,
Thank you for responding. I could restructure the tests so that I copy in test data before running the tests. At this point, I haven't even began on the application but there is an integration module in the application that will need to use nested transactions and having this fail now makes me nervous. I suppose I should create that test now. David Morris Show quote "Frans Bouma [C# MVP]" wrote: > David Morris wrote: > > > Hello, > > > > I am trying to set up some nested transactions to speed up a group of > > unit tests. The unit tests call a common method to build up some test > > data, which takes about 30 seconds and then runs a specific test. > > Each C# unit tests has a using statement that creates a new new > > TransactionScope(TransactionScopeOption.Required, timeSpan) (timeSpan > > is 600 seconds). Data access uses the Patterns and Practices > > Enterprise Library 2.0 against a SQL Server 2005 database. > > > > It all works fine but I would like to speed up my total test time and > > only create the test data once. I added [ClassInitialize()] and > > [ClassCleanup()] methods to run when my unit tests start and end. In > > the ClassInitialize method I created a > > TransactionScope(TransactionScopeOption.Required, timeSpan) and in > > the ClassCleanup I added a transactionScope.Dispose(); In each test, > > I created a TranactionScop(TransactionScopeOption.RequiresNew, > > timeSpan) both with a duration of 5 minutes. Now I am getting a > > timeout error. > > > > "Error retrieving data for the query from command with CommandText of > > xxx: Timeout expired. The timeout period elapsed prior to > > completion of the operation or the server is not responding." (where > > xxx is a select stored procedure name) > > > > If I replace RequiresNew with Required in the individual tests, the > > first test works and subsequent tests fail, which makes sense because > > it appears to join and roll back the outer ambient transaction. > > > > Does anyone know why nesting I would get the timeout at about 30 > > seconds with the RequiresNew? > > I don't see where you're nesting transactions: nested transactions are > done using nested using statements. For example: it's not said that the > start/end methods of the test fixture are ran in the same > thread/appdomain and neither is it defined in which order the tests are > ran. > > Unit tests should be atomic, thus shouldn't rely on order. If you need > test-data for your tests, I'd store it in a second schema in your db > and copy it over inside your db to your schema targeted by the tests, > either with a proc or with a sql statement. > > FB > > -- > ------------------------------------------------------------------------ > Lead developer of LLBLGen Pro, the productive O/R mapper for .NET > LLBLGen Pro website: http://www.llblgen.com > My .NET blog: http://weblogs.asp.net/fbouma > Microsoft MVP (C#) > ------------------------------------------------------------------------ > I now have a very simple unit test that has nested TransactionScope
statements. I now have code like this: TimeSpan timeSpan = TimeSpan.FromSeconds(600); using (TransactionScope transactionScope1, new TransactionScope(TransactionScopeOption.RequiresNew, timeSpan); --insert a record using Enterprise library --retrieve record count using (TransactionScope transactionScope2, new TransactionScope(TransactionScopeOption.RequiresNew, timeSpan) --insert a record using Enterprise library --retrieve record count --assert record count = original count + 1 } --assert record count = original count } If I use TransactionScopeOption.Required my second assert fails. If I use RequiresNew I get the timeout error after about 30 seconds. Thanks, David Morris David Morris wrote:
Show quote > I now have a very simple unit test that has nested TransactionScope Hmm. it seems the second insert isn't running in the same> statements. I now have code like this: > > TimeSpan timeSpan = TimeSpan.FromSeconds(600); > using (TransactionScope transactionScope1, new > TransactionScope(TransactionScopeOption.RequiresNew, timeSpan); > --insert a record using Enterprise library > --retrieve record count > using (TransactionScope transactionScope2, new > TransactionScope(TransactionScopeOption.RequiresNew, timeSpan) > --insert a record using Enterprise library > --retrieve record count > --assert record count = original count + 1 > } > --assert record count = original count > } > > If I use TransactionScopeOption.Required my second assert fails. If I > use RequiresNew I get the timeout error after about 30 seconds. transaction, as it apparently can't see what the first statement has done and the requirednew simply starts a new transaction and this of course hangs on the record count due to a lock on the row by the first transaction. If you pass in the first transactionscope's transaction into the second using statement, does it work then? (not really logical, but just for testing) FB -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------ Yes, it works if i share the first ambient transaction except the rollback
triggered by the first dispose rolls back both inserts. If I don't share the transaction the failure is on the inner insert, which happens before the count. It could be that something that happens in Enterprise Library 2.0 Data Access Block that contributes to this failure but I don't know where to begin looking. Version 3.0 added better support for TransactionScope so that connections are shared to avoid a distributed transaction but I can't upgrade yet because there were some changes that are not backward compatable. --David Morris Thanks, David Morris Show quote "Frans Bouma [C# MVP]" wrote: > David Morris wrote: > > > I now have a very simple unit test that has nested TransactionScope > > statements. I now have code like this: > > > > TimeSpan timeSpan = TimeSpan.FromSeconds(600); > > using (TransactionScope transactionScope1, new > > TransactionScope(TransactionScopeOption.RequiresNew, timeSpan); > > --insert a record using Enterprise library > > --retrieve record count > > using (TransactionScope transactionScope2, new > > TransactionScope(TransactionScopeOption.RequiresNew, timeSpan) > > --insert a record using Enterprise library > > --retrieve record count > > --assert record count = original count + 1 > > } > > --assert record count = original count > > } > > > > If I use TransactionScopeOption.Required my second assert fails. If I > > use RequiresNew I get the timeout error after about 30 seconds. > > Hmm. it seems the second insert isn't running in the same > transaction, as it apparently can't see what the first statement has > done and the requirednew simply starts a new transaction and this of > course hangs on the record count due to a lock on the row by the first > transaction. > > If you pass in the first transactionscope's transaction into the > second using statement, does it work then? (not really logical, but > just for testing) > > FB > > -- > ------------------------------------------------------------------------ > Lead developer of LLBLGen Pro, the productive O/R mapper for .NET > LLBLGen Pro website: http://www.llblgen.com > My .NET blog: http://weblogs.asp.net/fbouma > Microsoft MVP (C#) > ------------------------------------------------------------------------ > Hi David,
What the different between REQUIRED and REQUIRESNEW is that REQUIRESNEW will always create a new transaction for the scope. I'm afraid it could be a fault in Enterprise Library 2.0 Data Access Block, but it is really difficult to trouble shoot such issue.... However, you may consider have Data Access tracing, so you can see what's really happening. Have a look at the following document. http://msdn2.microsoft.com/en-us/library/ms971550.aspx [Tracing Data Access] Hope this helps. Sincerely, Wen Yuan Microsoft Online Community Support |
|||||||||||||||||||||||