TransactionScope is not rolling back in MSTest test - c#

I have the following base object in my Tests
[TestClass]
public abstract class TestClassBase
{
private TransactionScope _transactionScope;
[TestInitialize]
public virtual void TestInitialize()
{
_transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { Timeout = new TimeSpan(0, 10, 0) });
}
[TestCleanup]
public virtual void TestCleanup()
{
_transactionScope.Dispose();
}
}
I have a Test that does the following
[TestMethod]
public void SaveToDatebaseTest(
{
Program program = new Program();
program.Name = "Unit Test Program, I should not exists, when Test is done";
ProgramManager programManager = new ProgramManager()
programManager.Save(program);
}
When I run the test, the records still exists in the database.
I want to avoid using TransactionScope within every test method

You need to change your TestCleanup method, right now you Dispose of the TransactionScope, I believe that is actually doing an implicit commit? (you would think you would need to call Complete() though?), since there are no errors it is not Rolling back the transaction.
try this
[TestCleanup]
public virtual void TestCleanup()
{
// using System.Transactions;
Transaction.Current.Rollback();
_transactionScope.Dispose();
}

i know this question is kind of old, but it may help out someone who might/will be struggling on this in the future like i just did earlier. so if you're using
Entity Framework
Nunit (v3)
the code below won't work.
class A
{
private TransactionScope _trans;
[SetUp]
public void setup()
{
_trans = new TransactionScope();
}
[TearDown]
public void done()
{
if(_trans != null)
_trans.Dispose();
}
[Test]
public void doSomeDbWrite()
{
//your code to insert/update/delete data in db
}
}
I have tried (and doesn't work) creating the TransactionScope before creating the DB Context or the other way around. I think it has something to do with EF itself which i suppose is encapsulated in their own transactions or whatever. i did not dig deeper on that part. anyway, here's how i did it with EF and transactions to ensure that your unit test DB is clean after the unit test is done.
class A
{
private DbContext_DB;
private DbContextTransaction _trans;
[SetUp]
public void setup()
{
DB = new DbContext();//create your db context
_trans = DB.Database.BeginTransaction();
}
[TearDown]
public void done()
{
_trans.Rollback();
DB = null;
}
}
Hopefully it will help others searching for this at this time :-)

In .NET Core async Task [TestInitialize] methods are unsupported and will result in the behaviour you describe.
Async [TestInitialize] methods appear to run in a different thread context to the [TestMethod] itself, even if TransactionScopeAsyncFlowOption.Enabled is set in the TransactionScope's options. Transaction.Current will be null in the test method and any changes will not be rolled back when [TestCleanup] disposes the TransactionScope.
Unfortunately there are no plans to support async flow in TestInitialize methods despite this working in older versions of .NET (.NET Framework 4.8 at least).
The only work around at present is to make the [TestInitialize] method non-async and .Wait() / .Result your async calls but please upvote the GitHub issue above to show support for this feature.

If you are using VS2005 or VS2008 (not sure about 2010), you can try MSTestExtensions for automatic database transaction rollback after tests methods are completed. I've used it with MS SQLServer and it's Distributed Transaction Coordinator service running.
I know this may not be exactly what you are looking for, but it may be of help to your situation.

I think what you are trying to achieve here is to create a generic Test class that implements the initialize and cleanup so you don't have to repeat that code for every test, is that correct? Are you even sure that those methods are even called? Be aware that you can't subclass [TestInitialize] and [TestCleanup], so you would have to call those methods from the sublcass. (See https://stackoverflow.com/a/15946140/1638933).

I have the same issue but I used the following code to fix the issue Maybe it can help you:
private readonly TransactionScope _scope;
public MyTests()
{
var options = new TransactionOptions()
{
IsolationLevel = IsolationLevel.Snapshot
};
_scope = new TransactionScope(TransactionScopeOption.Required, options, TransactionScopeAsyncFlowOption.Enabled);
}
[TestCleanup]
public void Cleanup()
{
_scope.Dispose();
}

Related

MSTest V2 Execute UnitTests sequentially -> [DoNotParallelize]

I have a question on running UnitTests sequentially. Unfortunately in scenario it is not an option to run them parallel or mock the database. The project is written in .NET core 3.1 and the UnitTests need to execute database operations before and after a Unittest has run.
After reading https://www.meziantou.net/mstest-v2-execute-tests-in-parallel.htm and a lot of other articles about sequential UnitTesting I came up with this (simplified):
BaseClass:
namespace XY.Test
{
[TestClass]
public class BaseTest: TimerModel
{
private static readonly DbCreator Creator = new DbCreator();
public static readonly DbConnectionManager ConnectionManager = new DbConnectionManager();
[TestInitialize]
public void BaseTestInitialize()
{
CreateTestData();
}
[TestCleanup]
public void BaseTestCleanup()
{
RemoveTestData();
}
public void CreateTestData()
{
RemoveTestData();
Creator.ExecuteSqlFromScript(ConnectionManager, #"Resources\CreateTestData.sql");
}
public void RemoveTestData()
{
Creator.ExecuteSqlFromScript(ConnectionManager, #"Resources\EmptyTestDataTables.sql");
}
}
}
TestClass:
[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.ClassLevel)] //<-- Also tried out Workers = 1 and Scope = ExecutionScope.MethodLevel
namespace XY.Test.Models
{
[TestClass]
public class TerminalConfigModelTest: BaseTest
{
[TestMethod]
[DoNotParallelize]
public void TestMethod1()
{
...
}
[TestMethod]
[DoNotParallelize]
public void TestMethod2()
{
...
}
}
}
For some reason, no matter what I do, the UnitTests are being executed parallel. What do I have to change in order to have them executed sequentially?
When I execute all tests in the test class, the TestInitialize of the base class is called twice before the TestCleanup is run. This causes the CreateTestData method to fail as indexes prevent a double insert of the test data.
What I would expect:
TestInitialize1 is called
TestMethod1 is executed
TestCleanup1 is called
TestInitialize2 is called
TestMethod2 is executed
TestCleanup2 is called
...
What happens:
TestInitialize1 is called
TestMethod1 is executed
TestInitialize2 is called before TestCleanup1 is called
TestMethod2 execution fails
Am I missunderstanding the [DoNotParallelize] option?
Paralelism isn't the problem here, my tests are definitely sequential and [ClassCleanup] also screwed me over. It's just unintuitive and weird, more info here.
I wanted to use ordered tests but it seems it's a legacy functionality only in MSTest-v1 and new versions of Visual Studio don't even support it.
Best thing i can tell you now is just don't use [ClassCleanup].
Use [TestCleanup] or [AssemblyCleanup].

Ninject with EF multithreading

Good morning everyone!
I just started working in the project where I see there is an memory leak.
The situtation is as below. There is a console application which basically runs all the time in the while(true) loop.
There are bunch on classes which does some logic in the loop.
Each class has Execute() method where inside create uses Task.Run() method where the call is not awaited by anyone.
The list of above classes are called Engines. All engines are stateless classes which are stored in in array in main Program.cs class.
The code basically looks like:
private static List<BaseEngine> Engines;
public static void Main(string[] args)
{
InitializeDI();
RunProgram();
}
private static void RunProgram()
{
while (true)
{
try
{
foreach (var engine in Engines)
{
engine.Execute();
}
}
catch (Exception ex)
{
//handle
}
finally
{
Thread.Sleep(TimeSpan.FromSeconds(3));
}
}
}
private static void InitializeDI()
{
_kernel = new StandardKernel();
ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(_kernel));
NinjectConfig.Setup(_kernel);
}
The sample engine looks like:
public class SampleEngine : BaseEngine
{
public override void Execute(Task task)
{
var someService = ServiceLocator.Current.GetInstance<IDbContext>();
System.Threading.Tasks.Task.Run(() =>
{
// some action using dbcontext
});
}
}
In above example of SampleEngine it uses to get IDbContext from Ninject DI. However other engines could use another services regiestred in DI.
All the dependencies are registered as InCallScope()
Basically its like mostly all engine its about fire and forget the given method using Task.Run().
What I did is changed Execute method to return the Task and after this task ran to completion I used to Dispose() this task. This did not bring any value.
I did some investigations and I saw that the problem is inside Ninject.Activation.Cache. I can do the manual cache clean which helps but I know the problem is somewhere in the code but I cannot find it.
Since every dependency is registered as InCallScope() they should be disposed after each task begin to the end. I dont see anything holding reference to these objects because every engine is stateless .
I used ANTS to see the some information and this just keeps growing each minute:
And this points to the Ninject caching as below:
Looks like the DbContext is not disposed and still exist in Ninject cache. Is it a problem of alot of tasks in the system or I do anything wrong ?
Thanks in advance
Cheers!
The most simple approach seems to be embedding the using in your task. But it is a blind shot, as it seems your code is simplified. You don't use the task parameter in your method.
public class SampleEngine : BaseEngine
{
public override void Execute(Task task)
{
System.Threading.Tasks.Task.Run(() =>
{
using (var someService = ServiceLocator.Current.GetInstance<IDbContext>())
{
// some action using dbcontext
}
});
}
}
For a more advanced approach, here is an interesting link. It features a InTaskScope binding. It is based on AsyncLocal and custom tasks through extensions of TaskFactory

How to create an aspect decorator to handle EF transactions

I'm working (maintaining) on a dll assembly that acts as a Data Access Layer, there are many methods that requires transaction handling, many other do not, it's a currently "functional" dll, without any transaction handling method, I need to add it, so I'm looking for an easy way to add a transaction handler.
I'm wondering if is it possible to use AOP to create a decorator that I can add to the methods that requires a transaction.
I would like to have something like this:
[Transaction]
void MyDbMethod()
{
//DoSomething
myContext.SaveChanges();
}
For the EF model definition I'm using Code First, the current project uses Unity framework for some other DI tasks, can that framework be used for this?
If someone faces this same issue, I did not found any "by hand" solution, instead I used the PostSharp library and its OnMethodBoundaryAspect class, but be careful, at this moment the free/express license has limitations about the amount of classes where you can use it, so read carefully its limitations.
using System.Transactions;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace MyProject
{
[PSerializable]
public class Transaction : OnMethodBoundaryAspect
{
public Transaction()
{
//Required if the decorated method is async
ApplyToStateMachine = true;
}
public override void OnEntry(MethodExecutionArgs args)
{
//TransactionScopeAsyncFlowOption.Enabled => Required if the decorated method is async
var transactionScope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled);
args.MethodExecutionTag = transactionScope;
}
public override void OnSuccess(MethodExecutionArgs args)
{
var transactionScope = (TransactionScope)args.MethodExecutionTag;
transactionScope.Complete();
}
public override void OnExit(MethodExecutionArgs args)
{
var transactionScope = (TransactionScope)args.MethodExecutionTag;
transactionScope.Dispose();
}
}
}
You can do it using NConcern .NET AOP Framework.
This is an open source runtime AOP framework on which I actively work.
public class DataAccessLayer : IAspect
{
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//define how to rewrite method
yield return Advice.Basic.Arround(invoke =>
{
using (var transaction = new TransactionScope(...))
{
invoke(); //invoke original code
transaction.Complete();
}
});
}
}
Your business
public class MyBusiness
{
[Transaction]
void MyDbMethod()
{
}
}
Attach transaction scope aspect to you business
Aspect.Weave<DataAccessLayer>(method => method.IsDefined(typeof(TransactionAttribute), true);

Entity framework code first unit tests that require empty database

I have a code that uses EF code first that I want to Unit tests in my unit test I want a real empty database in the start of the test so I did:
[TestInitialize]
public void Initialize()
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
}
[TestCleanup]
public void CleanUp()
{
MyContext db = new MyContext();
db.Database.Delete();
}
but because the tests run in parallel this is not work so I did a order test with my tests and it also
has issues because the database sometimes is not dropped because is in use...
Someone have better strategy? I thought maybe each test will create its own database ? if it is good idea how can I achieve this?
Please try this
[TestClass]
public class UnitTestClass
{
private static string testConnString;
[TestInitialize]
public void Initialize()
{
testConnString = GetTestConnString();
using (MyContext db = new MyContext(testConnString, new DropCreateDatabaseAlways<MyContext>()))
{
db.UnderlyingContext.Connection.Open();
}
}
[TestMethod]
public void TestMethod1()
{
}
[TestCleanup]
public void CleanUp()
{
using (MyContext db = new MyContext(testConnString))
{
db.Database.Delete();
}
}
private static string GetTestConnString()
{
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
csb.DataSource = #"MYPC\SQLEXPRESS"; // Replace it with your SQL-server name
csb.InitialCatalog = "DB"+Guid.NewGuid().ToString().Replace("-","");
csb.IntegratedSecurity = true;
return csb.ToString();
}
}
public class MyContext : DbContext
{
private static IDatabaseInitializer<MyContext> _Initializer;
public MyContext(string connString, IDatabaseInitializer<MyContext> initializer = null)
: base(connString)
{
_Initializer = initializer;
}
public ObjectContext UnderlyingContext
{
get { return (this as IObjectContextAdapter).ObjectContext; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (_Initializer != null)
{
Database.SetInitializer(_Initializer);
}
base.OnModelCreating(modelBuilder);
}
}
What does "real" mean? Have you considered using an in-memory DB in your unit tests? With an in-memory DB like SQLite you can set up a fresh DB for each test with relatively little overhead. You can also prepare a test database once, store it to a file, and load it for each test. Check out this answer. And this link. You'll find more if you Google a little.
I would try to avoid relying on an ordering. The tests should be independent from each other to allow for clear traceability from failed tests to issues in the code. A test should not fail only because another test manipulated shared data.
Another concern for me would be performance. With a mandatory ordering parallel test execution is out of the question. And if you use a production-like DB setting for all your tests, they will definitely be much slower than with an in-memory replacement.

How to write output in the [ClassInitialize()] of a Unit Test class?

I am writing some unit tests for the persistence layer of my C#.NET application. Before and after the tests of a test class execute, I want to do some cleaning up to erase possibly inserted dummy values, therefore, this cleaning up happens in methods marked with the attributes [ClassInitialize()] and [ClassCleanup()].
(I know that a better way would be to use an in-memory database, but it is not really doable so far as we depend on lots of stored procs....)
I would like to output some information about the results of the cleaning up, but I can not find a way to get the output in the test results with VISUAL Studio 2010.
This is what I am doing so far :
///... lots of stuff before ...
//global for the test run
private static TestContext context;
//for each test
private IRepository repo;
#region Initialisation and cleanup
/// <summary>
/// Execute once before the test-suite
/// </summary>
[ClassInitialize()]
public static void InitTestSuite(TestContext testContext)
{
context = testContext;
removeTestDataFromDb();
}
[ClassCleanup()]
public static void CleanupTestSuite()
{
removeTestDataFromDb();
}
private static void removeTestDataFromDb()
{
context.WriteLine("removeTestDataFromDb starting");
using (ISession session = NHibernateHelper.OpenSession())
{
IDbConnection cn = session.Connection;
IDbCommand cmd = cn.CreateCommand();
//remove anyt test data
cmd.CommandText = #"DELETE FROM SomeTable
WHERE somefield LIKE 'easyToFindTestData%Test'";
int res = cmd.ExecuteNonQuery();
context.WriteLine("removeTestDataFromDb done - affected {0} rows", res);
}
}
[TestInitialize()]
public void InitTest()
{
repo = new MyRepositoryImplementation();
}
[TestCleanup()]
public void CleanupTest()
{
//cleanup
repo = null;
}
#endregion
I'm trying to use context.WriteLine() ...
I also tried just using Console.WriteLine() with the same results.
How do you write to standard output in the ClassInitialize part and where can you access that output ?
The [ClassInitialize] and [ClassCleanup] run just once for all the tests in that class. You'd be better of using [TestInitialize] and [TestCleanUp] which run before and after each test. Also try wrapping the complete test in a database transaction. This way you can simply rollback the operation (by not committing the transaction) and your database stays in a consistent state (which is essential for trustworthy automated tests).
A trick I do for integration tests is to define a base class that all my integration test classes can inherit from. The base class ensures that each test is ran in a transaction and that this transaction is rolled back. Here is the code:
public abstract class IntegrationTestBase
{
private TransactionScope scope;
[TestInitialize]
public void TestInitialize()
{
scope = new TransactionScope();
}
[TestCleanup]
public void TestCleanup()
{
scope.Dispose();
}
}
Good luck.
The trace output from a ClassInitialize and ClassCleanup appears in the result summary.
You can access it by doing the following
Open the Test Results windw [ Test -> Windows -> Test Results ]
There should be a link named "Test run completed" on the top left corner of the [Test Results] window.
Click the clink
It should open a window with the header "Result Summary" and it will show the debug trace created during ClassInitialize and ClassCleanup
You can see the Console output on each test if you double-click the test method in the Test Results pane. It is also present in the .trx xml results file.
In addition, if you specify the "Define DEBUG constant", you can use the
System.Diagnostics.Debug.WriteLine("ClassInitialize Method invoked, yeah.");
.. which will end up in the "Output" pane.

Categories