ClassCleanup Method Runs Too Late (or After All ClassInitialize methods) - unit-testing

When running multiple [TestClass]es at the same time, why do the [ClassCleanup()] methods only get called at the very end?
File: UnitTest1.cs
[TestClass]
public class UnitTest1
{
[ClassInitialize()]
public static void ClassInit(TestContext context)
{
}
[ClassCleanup()]
public static void ClassCleanup()
{
}
[TestMethod]
public void TestMethod1()
{
}
}
File: UnitTest2.cs
[TestClass]
public class UnitTest2
{
[ClassInitialize()]
public static void ClassInit(TestContext context)
{
}
[ClassCleanup()]
public static void ClassCleanup()
{
}
[TestMethod]
public void TestMethod1()
{
}
}
The execution order is the following:
UnitTest2.ClassInit()
UnitTest2.TestMethod1()
UnitTest1.ClassInit()
UnitTest1.TestMethod1()
UnitTest2.ClassCleanup()
UnitTest1.ClassCleanup()
Notice that both [ClassCleanup] methods are executed at the end of the set; not after each TestClass is "done".
But I expected a different behavior:
UnitTest2.ClassInit()
UnitTest2.TestMethod1()
UnitTest2.ClassCleanup() - Expected
UnitTest1.ClassInit()
UnitTest1.TestMethod1()
UnitTest1.ClassCleanup() - Expected
Microsoft's Documentation - ClassCleanupAttribute Class says, "Identifies a method that contains code to be used after all the tests in the test class have run and to free resources obtained by the test class. "
But it appears to be run/executed late!
How do I fix this? Or find a way to execute a method from the same TestClass right before the next ClassInitialize method.

Related

Mstest [ClassCleanup] not executed at all in VS 2019

[ClassInitialize]
public static void BeforeCls(TestContext tc)
{
Console.WriteLine("ClassInitialize - Before Class");
}
[ClassCleanup]
public static void AfterCls()
{
Console.WriteLine("ClassCleanup - After Class");
}
[TestInitialize]
public void BeforeMethod()
{
Console.WriteLine("TestInitialize - Before Method");
}
[TestCleanup]
public void AfterMethod()
{
Console.WriteLine("TestCleanup - After Method");
}
[TestMethod]
public void TestMethod1()
{
Console.WriteLine("Test Method - 1");
}
Class cleanup is never executed in this code.
here is the Output
ClassInitialize - Before Class
TestInitialize - Before Method
Test Method - 1
TestCleanup - After Method
Invested a bit more time and discovered that using this will work within a test class:
[ClassCleanup(InheritanceBehavior.None))]
public static void ClassCleanup()
{
// Your code goes here
}
And using that will work for a derived test class:
[ClassCleanup(InheritanceBehavior.BeforeEachDerivedClass)]
public static void ClassCleanup()
{
// Your code goes here
}
You can read more about it here.
If the solution is not working for you no matter what, you can define IDisposable. The code will look something like this:
[TestClass]
public class DisposableBaseTest : IDisposable
{
// Your initialize methods
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposableUserBaseTest()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Your cleanup code
Console.WriteLine("ClassCleanup - After Class");
}
}
}
P.S. And according to carlin.scott from this post, if you receive an exception during ClassInitialize, you want to handle this separately.
ClassCleanup is executed - put a breakpoint inside your method and verify it yourself. Problem is, that this method is executed after all of your tests are completed, so you cannot write message from that method in test output report. This is similar to ClassInitialize method. If you have multiple tests in your file, your ClassInitialize will write a message to only one of them.

Nesting test runners

I am trying to find out whether and how it is possible to nest JUnit test runners, e.g. combine a GuiceJUnitRunner, a Parameterized and a HierarchicalcontextRunner.
To me, it seems that JUnit was not designed to achieve this easily, otherwise BlockJUnit4ClassRunner should have a method which passes the next Runner as an argument.
Someone also implemented a ParallelParameterized runner, which looks to me like combining Parallel and Parameterized was not easily possible.
When googling for "nested" and "JUnit", it comes up with lots of information for nested classes, but I'm looking for nesting Runners, not classes.
There is something called NestedRunner for running plain old Java classes in nested configuration.
your test starts with #RunWith(NestedRunner.class) and here is the example that I found:
#RunWith(NestedRunner.class)
public class ListTest {
// inner class for sharing common context
public class WithArrayList {
// some context for these tests
ArrayList<String> list = new ArrayList<String>();
public class WhenEmpty {
#Test
public void itIsEmpty() {
assertTrue(list.isEmpty());
}
public class AfterAddingAnElement {
// some more context for these tests
String element = "Element";
// you can use instance initializer to initialize your context
// it will be run once per test
{
// the list is still empty in here
assertTrue(list.isEmpty());
list.add(element);
}
#Test
public void itIsNotEmpty() {
assertFalse(list.isEmpty());
}
#Test
public void itContainsTheElement() {
assertTrue(list.contains(element));
}
#Test
public void addingAnotherElementIncreasesSize() {
int sizeBeforeAdding = list.size();
list.add("AnotherElement");
assertThat(list.size(), is(greaterThan(sizeBeforeAdding)));
}
#Test
public void listSizeIsStillOne() {
assertThat(list.size(), is(equalTo(1)));
}
}
#Test
public void isStillEmpty() {
assertTrue(list.isEmpty());
}
}
public class WithTwoElements {
#Before
public void init() {
list.add("Element1");
list.add("Element2");
}
#Test
public void hasSizeOfTwo() {
assertThat(list.size(), is(equalTo(2)));
}
}
}
}
and here is the source for further info

Nhibernate unit testing. Child class cannot use Base class property

I am using Fluent NHibernate and trying to do unit testing. Now I have a base test class which looks as follows:
[TestClass]
public abstract class BaseTest<TEntity> where TEntity : IBaseModel
{
private const string testDbFile = "test.db";
private static ISessionFactory sessionFactory;
protected static ISession session;
[TestMethod]
public void configureDB()
{
try
{
if (sessionFactory == null)
{
sessionFactory = Fluently.Configure()
.Database(SQLiteConfiguration.Standard
.UsingFile(testDbFile))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<AdminTest>())
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
}
}
private static void BuildSchema(Configuration config)
{
new SchemaUpdate(config).Execute(false, true);
}
[TestMethod]
public void sessionCreated()
{
session = sessionFactory.OpenSession();
}
[TestMethod]
public virtual void AddEntity_EntityWasAdded()
{
var entity = BuildEntity();
InsertEntity(entity);
session.Evict(entity);
var reloadedEntity = session.Get<TEntity>(entity.Id);
Assert.IsNotNull(reloadedEntity);
AssertAreEqual(entity, reloadedEntity);
AssertValidId(reloadedEntity);
}
There are also other methods which update and delete an entity. And I have AdminTest class which inherits BaseTest. In AdminTest I have following method:
[TestClass]
public class AdminTest : BaseTest<Admin>
{
[TestMethod]
public void SelectWorks()
{
IList<Admin> admins = session.QueryOver<Admin>().List();
Assert.AreNotEqual(0, admins.Count);
}
}
Here I always have exception, because session is null. Maybe I am wrong in the way of thinking how visual studio performs unit tests (I am newbie in it)?
Now I think like that, visual studio works in the following way
runs test-methods from BaseTest (there it configures database and creates session)
runs selectWorks method. Here I was thinking it should use session from BaseTest
Could you explain what is wrong in my way of thinking? And I want to be able to query from child classes, what is the right way of doing it?
Thanks, any help is appreciated, .
I would suggest using [TestInitialize] and [TestCleanup] in your abstract base class and doing something like the following:
[TestInitialize]
public void TestInitialize()
{
Console.Out.WriteLine("Get a ISession object");
}
[TestCleanup]
public void TestCleanup()
{
Console.Out.WriteLine("Dispose ISession");
}
Then in your child classes continue to do what you are doing:
[TestMethod]
public void DoDbWork()
{
Console.Out.WriteLine("Running a query via nhibernate");
}
You really just want to ensure you have a clean session for each test. The attributes for TestInitialize and TestCleanup will run before and after each unit test. Here is the documentation for those attributes.
To ensure your ISession is in the right state,follow something like this.

Unit Tests inheritance

How do i make Base class with [TestClass()], where i will do MyClassInitialize(), and after that, i will just make my another Test classes just like that - MyNewTest : BaseTest
and there will no initializing?
(using MSTest)
The ClassInitialize won’t work on a base class. It seems that this attribute is searched for only on the executed test class. However, you can call the base class explicitly.
Here is an example:
[TestClass]
public class MyTestClass : TestBase
{
[TestMethod]
public void MyTestMethod()
{
System.Diagnostics.Debug.WriteLine("MyTestMethod");
}
[ClassInitialize]
public new static void MyClassInitialize(TestContext context)
{
TestBase.MyClassInitialize(context);
}
}
[TestClass]
public abstract class TestBase
{
public TestContext TestContext { get; set; }
public static void MyClassInitialize(TestContext context)
{
System.Diagnostics.Debug.WriteLine("MyClassInitialize");
}
[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
}
}
In NUnit/MbUnit you simply put the Initalize/Cleanup methods with the respective attributes in the base class, then inherit from it.
I haven't tried this yet with MSTest, but I wouldn't recommend this framework anyway.
Thomas

Using inheritance in MSTest

I am setting up some MSTest based unit tests. To make my life easier I want to use a base class that handles the generic setup and taredown all of my tests require. My base class looks like this:
[TestClass]
public class DBTestBase {
public TestContext TestContext { get; set; }
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext) {
var config = new XmlConfigurationSource("ARconfig_test.xml");
ActiveRecordStarter.Initialize(Assembly.Load("LocalModels"), config);
}
[TestInitialize()]
public void MyTestInitialize() {
ActiveRecordStarter.CreateSchema();
Before_each_test();
}
protected virtual void Before_each_test() { }
[TestCleanup()]
public void MyTestCleanup() {
After_each_test();
}
protected virtual void After_each_test() { }
}
My actual test class looks like this:
[TestClass]
public class question_tests : DBTestBase {
private void CreateInitialData() {
var question = new Question()
{
Name = "Test Question",
Description = "This is a simple test question"
};
question.Create();
}
protected override void Before_each_test() {
base.Before_each_test();
CreateInitialData();
}
[TestMethod]
public void test_fetching() {
var q = Question.FindAll();
Assert.AreEqual("Test Question", q[0].Name, "Incorrect name.");
}
}
The TestInitialize function works as expected. But the ClassInitialize function never runs. It does run if I add the following to my child class:
[ClassInitialize()]
public static void t(TestContext testContext) {
MyClassInitialize(testContext);
}
Is it possible to get my base class initialize function to run without referencing it in my child class?
ClassInitialize method is executed if and only if the concerned "class" contains at least one TestMethod, and at least one TestMethod from the class is selected for execution.
Confirm this was a problem for me too. I used a constructor on the base and a destructor for the cleanup
[TestClass]
public class question_tests : DBTestBase {
...
[TestCleanup()]
public void TestCleanup()
{
base.MyTestCleanup();
}