I have a base class for my unit tests which sets up a simple transaction around every test.
public class TestBase
{
TransactionScope _trans;
[TestInitialize()]
public void Init()
{
_trans = new TransactionScope();
}
[TestCleanup()]
public void Cleanup()
{
_trans.Dispose();
}
}
In one of my inheriting classes I have a bunch of work I want to do once, before any of those tests are run - this should roll back after all tests for the class are completed.
[TestClass]
public class MyTests : TestBase
{
static TransactionScope _transClass;
[ClassInitialize()]
public static void ClassInit(TestContext context)
{
_transClass = new TransactionScope();
//do some setup
}
[ClassCleanup()]
public static void ClassCleanup()
{
_transClass.Dispose();
}
[TestMethod()]
public void TestMethod()
{
//do some testing
}
}
My actual class has multiple test methods of course. The first test method passes fine, but the second throws a TransactionAbortedException when it tries to set up a new TransactioScope in TestInitialize. Could someone please explain what I have set up wrong here?
I suspect the base class TestBase may be doing something with the connection after each test.
It's best to use transactions with using statement - it eliminates problems like yours.
Also having multiple tests in a single transaction is not a good idea, this means that the tests are interdependent. This leads to hard to track issues when a test passes or fails depending if it's run in a group or on its own.
In summary, I advice against having a member field for the transaction and instead use local variables with the using statement.
Related
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.
This question already has answers here:
xUnit.net: Global setup + teardown?
(6 answers)
Closed 2 years ago.
I am trying to test some code that uses a static class. The static class has a initialization method which can be called only once and throws exception if called second time. I have multiple test cases which tests the code that need to access the static class. In the code the initialization is done in startup.cs. How do I do something similar for test cases. I am using x-unit for unit testing.
public static class UniqueId
{
public static void Initialize()
{
if (_generator != null)
throw new Exception("Already initialized.");
_generator = new IdGenerator();
}
private static IdGenerator _generator = null;
public static BigId NextId()
{
if (_generator == null)
throw new Exception("Not initialized.");
return _generator.NextId();
}
}
Code that I want to test:
public string GenerateId
{
return UniqueId.NextId().ToString()
}
In your specific case, you need to set your class to implement the IDisposible and just call Dispose() when you want to destroy it.
Here a example:
namespace Prime.UnitTests.Services
{
[TestFixture]
public class YourClassTest
{
[SetUp]
public void SetUp()
{
//some configs...
}
[Test]
public void Test_size_String_1()
{
UniqueId.Initialize();
Assert.IsFalse(UniqueId.NextId().ToString() == 10); // quick example...
UniqueId.Dispose();
}
[Test]
public void Test_size_String_2XPTO()
{
UniqueId.Initialize();
Assert.IsFalse(UniqueId.NextId().ToString() == 115); // quick example...
UniqueId.Dispose();
}
}
}
public static class UniqueId : IDisposable
{
public static void Initialize()
{
if (_generator != null)
throw new Exception("Already initialized.");
_generator = new IdGenerator();
}
private static IdGenerator _generator = null;
public static BigId NextId()
{
if (_generator == null)
throw new Exception("Not initialized.");
return c.NextId();
}
public void Dispose()
{
_generator?.Dispose(); //Depends of the context of your IdGenerator
//or
_generator == null;
}
}
Assuming I understood, in MSTest, look into [TestInitialize], [ClassInitialize] (likely what you need) and see if either works for your use case for a "startup" function
[TestInitialize]
runs before all your unit tests (each)
[ClassInitialize]
runs once, the only official doc I can find these days is older...
ClassInitializeAttribute Class
Identifies a method that contains code that must be used before any of
the tests in the test class have run and to allocate resources to be
used by the test class. This class cannot be inherited.
Remarks
When run in a load test, the method marked with this attribute
will run once, and any initialization operations it performs will
apply to the entire test. If you need to do initialization operations
once for every virtual user iteration in the test, use the
TestInitializeAttribute.
The order that methods will be run is:
Methods marked with the AssemblyInitializeAttribute.
Methods marked with the ClassInitializeAttribute.
Methods marked with the TestInitializeAttribute.
Methods marked with the TestMethodAttribute.
Only one method in a class may be decorated with this attribute.
Important
This attribute should not be used on ASP.NET unit tests, that is, any
test with [HostType("ASP.NET")] attribute. Because of the stateless
nature of IIS and ASP.NET, a method decorated with this attribute may
be called more than once per test run.
Hth
It depends on which test framework you're using.
EDIT: I see now that you're using xUnit, but I'll leave the entire answer in case it's helpful to someone else.
xUnit
You can check this answer, which talks about how to create a global setup/teardown for a set of tests. To sum up that answer, if you create a constructor for your unit test class in Xunit, that method will be called before each test method. It also states:
A more optimized version would use the IClassFixture interface to
ensure that the global initialization/teardown functionality is only
called once. For this version, you don't extends a base class from
your test class but implement the IClassFixture interface where T
refers to your fixture class:
using Xunit;
public class TestsFixture : IDisposable {
public TestsFixture ()
{
// Do "global" initialization here; Only called once.
}
public void Dispose()
{
// Do "global" teardown here; Only called once.
} }
public class DummyTests : IClassFixture<TestsFixture> {
public DummyTests(TestsFixture data)
{
}
}
This will result in the constructor of TestsFixture only being run
once for every class under test. It thus depends on what you want
exactly to choose between the two methods.
If you're using NUnit it already has a OneTimeSetUp attribute you can use (docs here), like this:
[TestFixture]
public class MyTestFixture
{
[OneTimeSetUp]
public void OneTimeSetUp()
{
// Initialize things here; only called once
}
}
If you're using something other than xUnit and NUnit, check the documentation for the framework you use, and look for a one-time setup.
In visual studio 2012+, I am using Shims to allow the testing of legacy code without accessing the database. I am using the MSTest framework.
I am trying to avoid code duplication of setting up the shims multiple times; I have instead set up a helper method (e.g. below, BuildShim()) to do so. The idea is that by having the ShimObject built in the helper method, I can have it available for each of the Test methods in my test class.
In the constructor for the test class, I initialize a _idisposable = ShimsContext.Create() (which actually returns an IDisposable). In the methods, I have try {} and finally { _idisoposable.Close() };
Microsoft explicitly advises (see http://msdn.microsoft.com/en-us/library/hh549176.aspx ) using a ShimContext like this, however:
using (ShimsContext.Create()){
...
}
Questions:
Is it bad that I'm not doing it the Microsoft way? If I do it the Microsoft way, how can I avoid duplicating Shim setup code? Or it okay to put the ShimsContext initialization in the constructor and disposal in the finally {} blocks as long as I know what I'm getting into? (e.g. it might be bad if I were using ShimObject.AllInstances type methods, since I could accidentally affect a property in one place and inadvertently affect it elsewhere.)
Is there anything wrong creating the ShimsContext in the test constructor and disposing the _shimcontextDisposal in the finally block like this instead?
What happens if I don't dispose of ShimsContext? Will my computer blow up, figuratively? (e.g. will the shims never be unloaded and I would start to get weird behavior if I actually run the app?)
Example code below.
[TestClass()]
public class Tests {
//Variable to store ShimsContext idisposable. Note that we're not holding the ShimsContext,
//but rather the IDisposable object returned by the ShimsContext.Create() method
private IDisposable _shimscontextDisposable;
//Test class constructor
public Tests(){
_shimscontextDisposable = ShimsContext.Create();
}
//Test method
[TestMethod()]
public TestMethod1(){
try {
//Call the helper method below to get the shim
ShimObject shim = this.GetShimObject();
DataObject data = shim.Instance;
//... do something in test method 1
}
finally {
_shimscontextDisposable.Dispose();
}
}
//Test method 2
[TestMethod()]
public TestMethod2(){
try {
//Call the helper method below to get the shim
ShimObject shim = this.GetShimObject();
DataObject data = shim.Instance;
//... do something in test method 2
}
finally {
_shimscontextDisposable.Dispose();
}
}
//Reusable method to Build shims across methods, avoid duplicating shim setup
public ShimObject BuildShim(){
ShimObject shim = new ShimObject();
shim.TitleGet = () => { return "title"; };
shim.UrlGet = () => { return new Uri("http://www.google.com"); };
return shim;
}
For MSTest Unit Tests it is best practice not to use a constructor. Instead use the ClassInitialize or TestInitialize attribute methods, followed by the TestCleanup or ClassCleanup attribute methods.
For your case, you would set your IDisposable object in the Initialize and dispose of it in the Cleanup.
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.classinitializeattribute.aspx
namespace TestNamespace
{
[TestClass]
public class DivideClassTest
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
}
[TestInitialize]
public void Initialize()
{
}
[TestCleanup]
public void Cleanup()
{
}
[ClassCleanup]
public static void ClassCleanup()
{
}
}
}
I have to find info about the currently running UnitTest from a helper class' static method.
The Idea is getting a unique key from each test.
I thought about using TestContext, not sure if it is possible.
Exemple
[TestClass]
public void MyTestClass
{
public TestContext TestContext { get; set; }
[TestMethod]
public void MyTestMethod()
{
TestContext.Properties.Add("MyKey", Guid.NewGuid());
//Continue....
}
}
public static class Foo
{
public static Something GetSomething()
{
//Get the guid from test context.
//Return something base on this key
}
}
We are currently storing this key on the thread with Thread.SetData, but it is problematic if the tested code spawn multiple thread. For each thread I need to get the same key for a given unit test.
Foo.GetSomething() is not called from the unittest itself. The code calling it is a mock injected by Unity.
Edit
I'll explain the context a little bit, because it seems to be confusing.
The object created via unity is entity framework's context. When running unit tests, the context get its data in a structure that is created by Foo.GetSomething. Let's call it DataPersistance.
DataPersistance cannot be a singleton, because unit tests would impact each others.
We currently have one instance of DataPersistance per thread, witch is nice as long as the tested code is single threaded.
I want one instance of DataPersistance per unit test. If a could get an unique guid per test, I could resolve the instance for this test.
public static class Foo
{
public static Something GetSomething(Guid guid)
{
//Return something base on this key
return new Something();
}
}
Test:
[TestClass]
public void MyTestClass
{
public TestContext TestContext { get; set; }
[TestMethod]
public void MyTestMethod()
{
Guid guid = ...;
Something something = Foo.GetSomething(guid);
}
}
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.