NUnit TestFixtureSetUp runs multiple times? - c#

I have a basic Test setup using NUnit 2.6 and Visual NUnit in Visual Studio 2010. My problem is that when I'm running all tests it seems like the FixtureSetup method (which has the TestFixtureSetUpAttribute) is running one time for each of the tests.
I've also tried to put the Init code to the constructor, but it gives the same results.
The tests themselves reports their run time to runtime like 0.003 and 0.032 and so on.
[TestFixture]
public class MODatabaseTests
{
[TestFixtureSetUp]
public static void FixtureSetup()
{
// Perform heavy init (~1.5s)
}
[Test]
public void TestA()
{
...
}
[Test]
public void TestB()
{
...
}
}

If you add this code, you can confirm your suspicion:
private static bool initialized = false;
[TestFixtureSetUp]
public static void FixtureSetup()
{
if (initialized) Assert.Fail("fixture setup called multiple times");
initialized = true;
...
}
The test runner may calling every test individually instead of treating a TestFixture as a suite of tests.
As an aside, I would avoid static in unit tests because if you have any static variables, their state would be carried from each run (though the fixture kind of wants this) and you lose the "unit" part of unit testing.

Related

NUnit - Unit Test - Dispose issue

namespace Game.SoccerGame
[TestFixture]
public class Score_is_0_0 : SoccerGame
{
[SetUp]
public void SetUp()
{
GivenTheScoreIs(0,0);
}
[TearDown]
public void CleanUp()
{
}
[Test]
public void When_Team1_Scores()
{
WhenTeam1Scores();
Assert.That(ScoreOutput, Is.EqualTo("1:0"));
}
[Test]
public void When_Team2_Scores()
{
WhenTeam2Scores();
Assert.That(ScoreOutput, Is.EqualTo("0:1"));
}
}
Expected:
When_Team1_Scores() = 1:0
When_Team1_Scores() = 0:1
When I run the tests individually they work as expected.
The issue I am having is when I run the tests in the class all at the same time. When I do this the results are:
When_Team1_Scores() = 1:0
When_Team1_Scores() = 1:1
the ScoreOutput keeps its state after the first test and thus my second test fails
What is the best approach the kill the state in-between tests in the TearDown?
I have the object below in a separate class SoccerGame that I inherit that controls the score state
public abstract class SoccerGame : IDisposable
private SetScore currentScore = new SetScore();
protected string ScoreOutput => currentScore.ToString();
public void Dispose()
{
}
I tried to use IDisposable but it doesn't see to work or I am implementing it wrong?
When using NUnit, a single instance of the fixture is created and used for all the tests in the fixture. Because of that, any state that needs to be initialized should be taken care of in the SetUp method, which runs before each test.
You don't show the code for your method GivenTheScoreIs but it sounds like it's supposed to initialize the score. To ensure that it is working correctly, add a test that verifies the score is set (0:0).
The above should work. However, I recommend going a step further and not inheriting from SoccerGame, which is presumably the class you are testing. While inheriting a test in this way is occasionally useful, it isn't the normal or the cleanest way to do it. It's better to separate your system under test from the tests themselves.
To do that, I suggest you instantiate a new SoccerGame for each test, doing so in the SetUp method. That will eliminate any possibility of state carrying over from one test to another since each test will use a new SoccerGame.

How can I tell that my program is under unit test environment

I have a console application. In release environment, it works perfectly at this time. When in IDE debug environment, I don't want the console window close, so I added this function, and calling it in the very end of my program.
[Conditional("DEBUG")]
public static void DebugWaitAKey(string message = "Press any key")
{
Console.WriteLine(message);
Console.ReadKey();
}
It works well for me, when I debug my program. But with unit testing, it still wait for a key before exiting!
The work-around is only unit-testing release edition of my program, or test other functions. But I do want something can identify current session is under unit testing, and use that flag in this function.
I believe this should answer your question. I took a class from there and adapted it to your situation.
/// <summary>
/// Detects if we are running inside a unit test.
/// </summary>
public static class UnitTestDetector
{
static UnitTestDetector()
{
string testAssemblyName = "Microsoft.VisualStudio.QualityTools.UnitTestFramework";
UnitTestDetector.IsInUnitTest = AppDomain.CurrentDomain.GetAssemblies()
.Any(a => a.FullName.StartsWith(testAssemblyName));
}
public static bool IsInUnitTest { get; private set; }
}
Then I added a line to your method which if it is running a test it will not hit the Console.ReadKey();
[Conditional("DEBUG")]
public static void DebugWaitAKey(string message = "Press any key")
{
Console.WriteLine(message);
if(!UnitTestDetector.IsInUnitTest)
Console.ReadKey();
}
Note: This would be considered a hack and would not be considered a best practice.
EDIT:
I also created a sample project on github to demonstrate this code. https://github.com/jeffweiler8770/UnitTest
The simple way if your test runs from a dedicated UnitTest project : use a flag in AppSettings...
I would not investigate around patterns for such a purpose, i would run the test in a dedicated UnitTest project with its own configuration.
If you need to collect data maybe should you simply use traces (they can be customized from your .config file)... ?
Hope this helps...
Rather than looking for whether the program was compiled in debug mode, you can look at whether a debugger is attached:
if (Debugger.IsAttached)
{
Console.WriteLine(message);
Console.ReadKey();
}
Note this will only detect if you start with F5 from Visual Studio, not Ctrl-F5 (i.e. Start with Debugging only)
I used a variation of Jeff's UnitTestDetector. I did not want to check the unit test assembly and wanted to control which unit tests would consider this or not.
So I created a simple class with IsInUnitTest defaulting to false.
Then in the unit test classes where I wanted the conditional code to run I added TestInitializer and TestCleanup where I set the bool accordingly.
Then in my regular code I can use UnitTestDetector.IsInUnitTest
Simple UnitTestDetector class:
/// <summary>
/// Detects if we are running inside a unit test.
/// </summary>
public static class UnitTestDetector
{
static private bool _isInUnitTest = false;
public static bool IsInUnitTest
{
get { return _isInUnitTest; }
set { _isInUnitTest = value; }
}
}
Unit Test to Test this stuff:
[TestClass]
public class UnitTestDetectorTest_WithoutIsInUnitTest
{
[TestMethod]
public void IsInUnitTest_WithoutUnitTestAttribute_False()
{
bool expected = false;
bool actual = UnitTestDetector.IsInUnitTest;
Assert.AreEqual(expected, actual);
}
}
[TestClass]
public class UnitTestDetectorTest_WithIsInUnitTest
{
[TestInitialize()]
public void Initialize()
{
UnitTestDetector.IsInUnitTest = true;
}
[TestCleanup()]
public void Cleanup()
{
UnitTestDetector.IsInUnitTest = false;
}
[TestMethod]
public void IsInUnitTest_WithUnitTestAttribute_True()
{
bool expected = true;
bool actual = UnitTestDetector.IsInUnitTest;
Assert.AreEqual(expected, actual);
}
}
Condition in Code:
if (UnitTestDetector.IsInUnitTest)
return "Hey I'm in the unit test :)";
I know this is old but I really don't like many of these answers, especially anything that hard codes an assembly name or version.
This works well, as long as the class you are testing is not Sealed. It's pretty simple:
Add this class variable to the class you are testing:
protected Boolean IsInUnitTestMode = false;
We default it to false so in production it will always be false.
Add something like this wrapper to your test class
class ProfileTest : Profiles
{
public ProfileTest() : base()
{
IsInUnitTestMode = true;
}
}
In this example Profiles is the class we are testing, ProfileTest is a wrapper class in the test project's namespace. It will never be deployed. The test class uses this to create an instance of the class to be tested:
ProfileTest profiles = new ProfileTest();
As opposed to this:
private Profiles profiles = new Profiles();
The we can use it something like this:
private string ProfilePath
{
get
{
if (IsInUnitTestMode)
return SafeStorage.EnsureFolderExists(Path.Combine(SafeStorage.UserPath, UNITTESTFOLDERNAME)).FullName;
else
return SafeStorage.EnsureFolderExists(Path.Combine(SafeStorage.UserPath, PROFILEFOLDERNAME)).FullName;
}
}
As I said, this won't work with sealed classes, nor will it work well with static ones. With that said the number of times I actually choose to test for the unit test condition is quite rare. This works extremely well for me.

VS Team Test: Multiple Test Initialize Methods in Test Class

I have unit test project called “MyClassTest” in TeamTest. This project has three TestMethods. Each method needs its own test initialization steps. But when I apply TestInitializeAttribute to three initialization methods, it says the attribute should not be used more than once. Then what should be the attribute to be used to initialize each test method in Visual Studio Team Test?
Reference:
VS Team Test: .Net Unit Testing with Excel as Data Source: Adapter Failed
How to create Startup and Cleanup script for Visual Studio Test Project?
VS 2010 Load Tests Results with custom counters
How to log unit test entry and leave in MSTest
Can a unit test project load the target application's app.config file?
According to MSDN the TestInitializeAttribute:
cannot be used more than once (AllowMultiple = false), and
cannot be inherited to create your own TestInitializeAttribute.
So, my suggestion is to create the Test Initialize Methods without the TestInitialize attribute. Then in the unique TestInitialize method check which is the current executed TestMethod and call the appropriate initialize method:
[TestClass]
public class UnitTest
{
public TestContext TestContext { get; set; }
[TestInitialize]
public void Initialize()
{
switch (TestContext.TestName)
{
case "TestMethod1":
this.IntializeTestMethod1();
break;
case "TestMethod2":
this.IntializeTestMethod2();
break;
default:
break;
}
}
[TestMethod]
public void TestMethod1()
{
}
[TestMethod]
public void TestMethod2()
{
}
public void IntializeTestMethod1()
{
//Initialize Test Method 1
}
public void IntializeTestMethod2()
{
//Initialize Test Method 2
}
}
If you have three test methods, and each method has its own initialization steps, then why are you moving initialization to method which will run before every test? Only benefit I see, is that nice switch block, which adds some lines to your source file. But it gives you drawback - looking on any of these test methods, you can't really tell in which context method will be executed. So, I use initialization method to setup only basic context, which is really used by all tests in fixture.
Just move context creation to arrange part of each method.
If you have several methods, which use common context, then just extract method, which will setup context for them, and call it at the arrange part. You also can split each context setup to several steps and reuse those steps (like it done in Given-When-Then tools like Specflow).
And, of course, creating different fixtures also option.
It's a bit of an old post, but I came up with the following which seems to work OK:
First, define an attribute class:
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class InitialiseWithAttribute : Attribute
{
public string Id { get; private set; }
public InitialiseWithAttribute(string id)
{
Id = id;
}
}
then define an extension method in some convenient utilities class:
public static bool IsInitialisedWith(this string testName, string value)
{
bool result = false;
Type testClassType = new StackFrame(1).GetMethod().DeclaringType;
MethodInfo methodInfo = testClassType.GetMethod(testName);
if (methodInfo != null)
{
InitialiseWithAttribute initialiseWithAttribute =
methodInfo.GetCustomAttribute<InitialiseWithAttribute>(true);
if (initialiseWithAttribute != null)
{
result = initialiseWithAttribute.Id == value;
}
}
return result;
}
Now write your tests, thus:
public TestContext TestContext {get; set;}
[TestInitialize]
public void TestInitialise()
{
if (TestContext.TestName.IsInitalisedWith("DoSomethingSpecial")
{
// ... Do something special
}
else
{
// ... Do something normal
}
}
[TestMethod]
[InitialiseWith("DoSomethingSpecial")]
public void MySpecialTest()
{
// The test
}
If they need three seperate inits; then they should probably be in three separate fixtures each with their own init!
At my job we pass in an argument to TestInitialize method to determine how we want initialization to work.
public partial class CommonActions
{
public void TestInitialize(bool adminTest)
{
try
{
if (adminTest)
{
//do stuff
}
We then have a standard initialization in class definition, which defaults to false.
[TestClass]
public class ProjectTestBase : FrameworkTestBase
{
public CommonActions common { get; set; } = new CommonActions();
[TestInitialize]
public void TestInitialize() => common.TestInitialize(false);
Then in the Test cases themselves you can override the TestInitialize for any test you want.
[TestClass]
public class SetReportsInAdmin : ProjectTestBase
{
[TestInitialize]
public new void TestInitialize() => common.TestInitialize(true);
We use a Boolean to tell if Admin test, which needs to have extra overhead for setup. Take this and apply whatever variables you want in a way the gives you multiple initialization through the use of one method.

VS2010 doesn't "see" any of the tests in a new test class

I've created a class of Unit tests in an existing project (as opposed to creating a whole new test project)
When trying to run the tests via the Test menu VS claims that no tests are loaded..
How do I solve this ? (except for rewriting all the unit tests in Nunit, that is )
Editing to answer the questions:
the class and methods are public, [TestClass] and [TestMethod] annotations are all there
[TestClass]
public class FunctionalTests
{
[ClassInitialize()]
public void ClassInit()
{
//do init stuff
}
[TestMethod]
public void TestSomething()
{
//testing stuff
}
Check that the class has the [TestClass] attribute and that the tests methods has the [TestMethod] attribute. It happened to me once and this was the problem.
I gave up on trying to get sround VS2010 and created a new separate project for the tests, and all is well.
The ClassInitialize and ClassCleanup methods need to be static.
[ClassInitialize()]
public static void ClassInit()
{
}
[ClassCleanup]
public static void ClassCleanup()
{
}

Unit tests logged (or run) multiple times

I have this simple test:
protected readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().ReflectedType);
private static int count = 0;
[Test]
public void TestConfiguredSuccessfully()
{
logger.Debug("in test method" + count++);
}
log4net is set up like this:
[TestFixtureSetUp]
public void SetUp()
{
log4net.Config.BasicConfigurator.Configure();
}
The problem is, that if I run this test in nUnit once, I get the output (as expected):
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method0
But if I press RUN in nUnit.exe again (or more) I get the following:
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method1
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method1
And so on (if I run it 5 times, I'll get 5 repeating lines). Now, if I run the same test alone from reSharper the output is fine and does not repeat. However, if I run this test along side 2 other tests in the same class, the output is repeated three times.
I am totally confused. What the hell is going on here?
Log4net is being re-initialized on each test run, and appender(s) added each time. I suspect that ReSharper does not exhibit the behaviour as it starts a new process each time (the ReSharper test runner) whereas the NUnit GUI does not.
I have had various flavours of this in the past, but for quite a while now I have used a "SetupFixture" to initialize log4net (amongst other things).
[SetUpFixture]
public class UnitTestSuiteSetupTeardown
{
[SetUp]
public void Setup()
{
log4net.Config.BasicConfigurator.Configure();
}
[TearDown]
public void Teardown()
{
//Teardown stuff...
}
}
Add one of these per test assembly, and ensure the class has no namespace. It will be run once for all of your tests i.e. all tests in the assembly. I personally have one of these at solution level and then add it in as a link to each test project.
Update
The example above follows the question and sets up basic configuration. In my actual SetUpFixture I initialize log4net from a log4net configuration file (which I again store at solution level and then add as a link to all test projects), e.g.
[SetUpFixture]
public class UnitTestSuiteSetupTeardown
{
[SetUp]
public void Setup()
{
LogFactory.Configure();
}
[TearDown]
public void Teardown()
{
//Teardown stuff...
}
}
And a sample LogFactory type class.
public static class LogFactory
{
public const string DefaultConfigFileName = "log4net.config";
static ILog GetLogger(Type callingType)
{
return new Log4NetLogger(LogManager.GetLogger(callingType));
}
public static void Configure()
{
Type type = typeof(LogFactory);
FileInfo assemblyDirectory = AssemblyInfo.GetCodeBaseDirectory(type);
FileInfo configFile = new FileInfo(Path.Combine(assemblyDirectory.FullName,
DefaultConfigFileName));
XmlConfigurator.ConfigureAndWatch(configFile);
log4net.ILog log = LogManager.GetLogger(type);
log.ToString();
}
}

Categories