I'd like to get the currently executing NUnit test in a helper method I'm using. We're actually using NUnit for integration tests here -- not unit tests. When a test finishes, we'd like to have the test clean up some log files when it's done. Currently, I've hacked around this using the StackFrame class:
class TestHelper
{
string CurrentTestFixture;
string CurrentTest;
public TestHelper()
{
var callingFrame = new StackFrame(1);
var method = callingFrame.GetMethod();
CurrentTest = method.Name;
var type = method.DeclaringType;
CurrentTestFixture = type.Name;
}
public void HelperMethod()
{
var relativePath = Path.Combine(CurrentTestFixture, CurrentTest);
Directory.Delete(Path.Combine(Configurator.LogPath, relativePath));
}
}
[TestFixture]
class Fix
{
[Test]
public void MyTest()
{
var helper = new TestHelper();
//Do other testing stuff
helper.HelperMethod();
}
[Test]
public void MyTest2()
{
var helper = new TestHelper();
//Do some more testing stuff
helper.HelperMethod();
}
}
This works just fine, except there are cases where I'd like to make the TestHelper class part of my fixture, like this:
[TestFixture]
class Fix
{
private TestHelper helper;
[Setup]
public void Setup()
{
helper = new TestHelper();
}
[TearDown]
public void TearDown()
{
helper.HelperMethod();
}
[Test]
public void MyTest()
{
//Do other testing stuff
}
[Test]
public void MyTest2()
{
//Do some more testing stuff
}
}
I can't simply make this class into a global fixture because sometimes a single test will use it more than once, and sometimes a test need not use it at all. Sometimes a test needs to attach specific properties to the TestHelper.... things like that.
As a result, I'd like to be able to somehow get the currently executing test without having to manually repeat the name of the fixture and test in the several thousand test cases I'm looking at.
Is there a way to get such information?
NUnit 2.5.7 has added an "experimental" TestContext class. One of the properties it contains is TestName. I haven't tried it, so I don't know whether the info is available in the TearDown method.
Moving the code you have in the TestHelper constructor to the HelperMethod would do the trick for you?
class TestHelper
{
public void HelperMethod()
{
string CurrentTestFixture;
string CurrentTest;
var callingFrame = new StackFrame(1);
var method = callingFrame.GetMethod();
CurrentTest = method.Name;
var type = method.DeclaringType;
CurrentTestFixture = type.Name;
var relativePath = Path.Combine(CurrentTestFixture, CurrentTest);
Directory.Delete(Path.Combine(Configurator.LogPath, relativePath));
}
}
By the looks is that you can't because the stack frame at the point of setup and teardown does not include the test method.
As for cleaning up log files it looks like you want to have a log file per test method. Perhaps in this case it might be better to either:
Use a random id as part of the log file name which you can clean up in the teardown of the helper class. If however the name of the test method is required to be part of the log file you could do..
You can implement IDisposable todo the cleanup
[Test]
public void MyTest()
{
using(new TestHelper())
{
... test goes here ...
}
}
Or use PostSharp to weave the above code as part of an attribute on your test method.
[Test, TestHelper]
public void MyTest()
{
...
}
[EDIT]
fixed formatting. Added IDisposable
Related
I would like to a repeat set of unit tests, having the same setup fixture (SetUpFixture), for different conditions.
i.e. set of tests use the same file as an input. The file is being set in the setup fixture. I would like to repeat the tests that use the set up fixture for different input file.
It's possible for TextFixture, but not for SetupFixture. Is there a workaround for this?
What you can do is to generate few input files and use the file name as a parameter for your test:
[TestFixture]
public class MyClass
{
[TestFixtureSetUp]
//[OneTimeSetUp] for NUnit 3
public void FixtureSetUp()
{
PrepareFile("a.txt");
PrepareFile("b.txt");
PrepareFile("c.txt");
}
[TestCase("a.txt")]
[TestCase("b.txt")]
[TestCase("c.txt")]
public void Test(string fileName)
{
var result = YourTestCode(fileName);
Assert.True(result); //whatever you need
}
}
You could use the TestFixtureAttribute to construct your test class with each data file. Migrating Anton's answer;
[TestFixture("a.txt")]
[TestFixture("b.txt")]
[TestFixture("c.txt")]
public class MyClass
{
string _filename;
public MyClass(string filename)
{
_filename = filename;
}
[TestFixtureSetUp]
//[OneTimeSetUp] for NUnit 3
public void FixtureSetUp()
{
PrepareFile(_filename);
}
[Test()]
public void Test()
{
var result = YourTestCode();
Assert.True(result); //whatever you need
}
}
If you want a more dynamic way you provide the data for the TestFixture, look at the TestFixtureSourceAttribute
I have a helper class which inherits from an Interface and has three dependencies.
public class StudentHelper : IStudentHelper
{
private readonly IUpdateStudentManager _updateStudentManager;
private readonly ISchedulerHelper _schedulerHelper;
public StudentHelper(
IUpdateStudentManager updateStudentManager,
ISchedulerHelper schedulerHelper)
{
_updateStudentManager = updateStudentManager;
_schedulerHelper = schedulerHelper;
}
// Rest of the class not shown here for brevity.
}
To test this I wrote a test class like so:
[TestClass]
public class StudentHelperTests
{
private Mock<StudentHelper> _studentHelperMock;
private Mock<IUpdateStudentManager> _updateStudentManagerMock;
private Mock<ISchedulerHelper> _schedulerHelperMock;
[TestInitialize]
public void Setup()
{
_updateStudentManagerMock = new Mock<IUpdateStudentManager>();
_schedulerHelperMock = new Mock<ISchedulerHelper>();
_studentHelperMock = new Mock<StudentHelper>(_updateStudentManagerMock.Object,
_schedulerHelperMock.Object);
}
[TestMethod]
public void Calling_GetEndDate_Returns_A_FutureDate()
{
_productRulesHelper.Setup(x=>x.GetEndDate(DateTime.UtcNow.ToShortDateString(),1)).Returns(DateTime.UtcNow.AddYears(1).ToString("MM/dd/yyyy"));
_productRulesHelper.VerifyAll();
}
}
The method to test returns this error:
Test method StudentHelperTests.Calling_GetEndDate_Returns_A_FutureDate
threw exception:
System.NotSupportedException: Invalid setup on a non-virtual
(overridable in VB) member: x =>
x.GetEndDate(DateTime.UtcNow.ToShortDateString(), 1)
The GetEndDate method just takes in a date as string, adds a year and returns the resulting date as string.
I think the way StudentHelperMock is initialized is not correct!!!
Can someone please guide me on this?
Thanks in advance.
You're not supposed to create a mock for the instance you're trying to test - you're supposed to create a mock for its dependencies.
The purpose of mocking is to isolate the system under test (StudentHelper) from its dependencies (IUpdateStudentManager, ISchedulerHelper) by replacing them with test doubles (e.g. mocks).
Here's what your test case should look like:
[TestMethod]
public void Calling_GetEndDate_Returns_A_FutureDate()
{
// Arrange
var helper = new StudentHelper(_updateStudentManagerMock.Object, _schedulerHelperMock.Object);
var now = DateTime.UtcNow;
// Act
var result = x.GetEndDate(now.ToShortDateString(),1);
// Assert
Assert.Equal(now.AddYears(1).ToString("MM/dd/yyyy"), result);
}
On a side note: I would also advise against the usage of global test setups. See: Why you should not use SetUp and TearDown in NUnit.
Related reading:
The Little Mocker by Uncle Bob
When to Mock by Uncle Bob
Try something like this:
[TestClass]
public class StudentHelperTests
{
private StudentHelper _objectToTest;
private Mock<IUpdateStudentManager> _updateStudentManagerMock;
private Mock<ISchedulerHelper> _schedulerHelperMock;
[TestInitialize]
public void Setup()
{
_updateStudentManagerMock = new Mock<IUpdateStudentManager>();
_schedulerHelperMock = new Mock<ISchedulerHelper>();
_studentHelperMock = StudentHelper(_updateStudentManagerMock.Object,
_schedulerHelperMock.Object);
}
[TestMethod]
public void Calling_GetEndDate_Returns_A_FutureDate()
{
// The method name says:
var retrievedDate = _objectToTest.GetEndDate();
Assert()//... And you should verify than the retrieved date is "a future date"
}
}
Here is an example where I am testing the line if (true). But although the condition is obviously true, Moq tells me the method was never called.
public class test
{
public virtual void start()
{
if (true)
called();
}
public virtual void called()
{
}
}
[Test]
public void QuickTest()
{
var mock = new Mock<test>();
mock.Object.start();
mock.Verify(t => t.start(), "this works");
mock.Verify(t => t.called(), "crash here: why not called?");
}
How do I test that the method call to called() has happened?
I thought Moq was the solution, but from the comments it looks like it isn't so I've made another example without any reference to Moq:
public class test
{
public bool condition = true;
public test(bool cond)
{
condition = cond;
}
public virtual string start()
{
var str = "somestuff";
if (condition)
str += called();
str += "something more";
return str;
}
public virtual string called()
{
return "something more";
}
}
[Test]
public void ConditionTrue_CallsCalled()
{
var t = new test(true);
t.start();
//syntax? t.HasCalled("called");
Assert.IsTrue(result.Contains("something more"));
}
[Test]
public void ConditionFalse_NoCall()
{
var t = new test(false);
t.start();
//syntax? t.HasNotCalled("called");
// Can't check this way because something more is already being added
Assert.IsFalse(result.Contains("something more"));
}
Is it possible to do this? Is it worthwhile?
Regarding the first piece of code:
mock is a mock object. That means all the methods are overridden and do nothing. So it's entirely normal that calling mock.start() doesn't do anything and called() is never called.
If you want to mock just called() and use the real implementation of start(), you need to do partial mocking.
But I would advise against that, I would even advise against trying to test just this class. You will couple your test code too tightly to your implementation code. Think about doing TDD: ask yourself what feature of your application breaks if that if test is not there. Write a test against that feature, which should fail. Then write the if test to fix the test.
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.
I'd like to be able to test a class initialises correctly using Moq:
class ClassToTest
{
public ClassToTest()
{
Method1(#"C:\myfile.dat")
}
public virtual void Method1(string filename)
{
// mock this method
File.Create(filename);
}
}
I thought I'd be able to use the CallBase property to create a testable version of the class, then use .Setup() to ensure Method1() does not execute any code.
However, creating the Mock<ClassToTest>() doesn't call the constructor, and if it did it'd be too late to do the Setup()!
If this is impossible, what is the best way round the problem whilst ensuring that the constructor behaves correctly?
EDIT: To make it clearer, I've added a parameter to Method1() to take a filename and added some behaviour. The test I'd like to write would be a working version of the following:
[Test]
public void ClassToTest_ShouldCreateFileOnInitialisation()
{
var mockClass = new Mock<ClassToTest>() { CallBase = true };
mockClass.Setup(x => x.Method1(It.IsAny<string>());
mockClass.Verify(x => x.Method1(#"C:\myfile.dat"));
}
Way down inside of Moq.Mock (actually inside the CastleProxyFactory that Moq uses)
mockClass.Object
will call the constructor by way of Activator.CreateInstance()
So your test would look something like
[Test]
public void ClassToTest_ShouldCreateFileOnInitialisation()
{
Mock<ClassToTest> mockClass = new Mock<ClassToTest>();
mockClass.Setup(x => x.Method1(It.IsAny<string>());
var o = mockClass.Object;
mockClass.Verify(x => x.Method1(#"C:\myfile.dat"));
}