Find out the next test method to execute in MS TestInitialize - c#

I keep the test data for specific test method in folder named the same as function. I previously had the same function call in each [TestMethod], ClearAllAndLoadTestMethodData() which determined the method name via StackTrace. Now, I moved this function to [TestInitialize]. How can I find the name of the method that is about to be executed?
I thought TestContext provide this. I have access to it via [AssemblyInitialize()] and on first run its property Name is set to name of the testmethod. However, later this doesn't change (if I save the object in static field).

The AssemblyInitialize method is executed only once before all your tests.
Use the TestContext inside the TestInitialize method:
[TestClass]
public class TestClass
{
[TestInitialize]
public void TestIntialize()
{
string testMethodName = TestContext.TestName;
}
[TestMethod]
public void TestMethod()
{
}
public TestContext TestContext { get; set; }
}

[TestClass]
public class MyTestClass
{
private static TestContext _testContext;
[ClassInitialize]
public static void TestFixtureSetup(TestContext context)
{
_testContext = context;
}
[TestInitialize]
public void TestIntialize()
{
string testMethodName = MyTestClass._testContext.TestName;
switch (testMethodName)
{
case "TestMethodA":
//todo..
break;
case "TestMethodB":
//todo..
break;
default:
break;
}
}
[TestMethod]
public void TestMethodA()
{
}
[TestMethod]
public void TestMethodB()
{
}
}

Related

UnexpectedArgumentMatcherException when calling Setup second time

I have these two tests (stripped to the bare bones to replicate the error):
[TestFixture]
public class CreditorMapperTests
{
private IAbcContext _AbcContext;
[SetUp]
public void Setup()
{
_AbcContext = Substitute.For<IAbcContext>();
_AbcContext.CompanyInfo.Returns(x => new CompanyInfo(Arg.Any<Guid>()));
}
[Test]
public void A()
{
Creditor publishDocument = new Creditor();
publishDocument.CompanyExternalId = _AbcContext.CompanyInfo.UniqueId;
}
[Test]
public void B()
{
Creditor publishDocument = new Creditor();
publishDocument.CompanyExternalId = _AbcContext.CompanyInfo.UniqueId;
}
}
public interface IAbcContext
{
CompanyInfo CompanyInfo { get; }
}
public class CompanyInfo
{
public CompanyInfo(Guid uniqueId)
{
UniqueId = uniqueId;
}
public readonly Guid UniqueId;
}
public class Creditor
{
public Guid CompanyExternalId { get; set; }
}
The Setup() for A() runs fine. However when Setup() is called for B(), I get this error:
NSubstitute.Exceptions.UnexpectedArgumentMatcherException : Argument
matchers (Arg.Is, Arg.Any) should only be used in place of member
arguments. Do not use in a Returns() statement or anywhere else
outside of a member call. Correct use:
sub.MyMethod(Arg.Any()).Returns("hi") Incorrect use:
sub.MyMethod("hi").Returns(Arg.Any())
This only happens when I run both tests by running all tests in that class.
If I run B() by itself, the Exception is not thrown.
Why does Setup() for B() fail only when run automatically after A()?
(nb. both tests are identical).
I'm using NUnit v3.8.1 and NSubstitute v2.0.3

Prevent TestInitialize running for one TestMethod method

I have a set of unit tests that require TestInitialize to run for them to work... however, there is one specific test that i'd love to be able to run without running TestInitialize. Is there a way to do that?
It might look like this:
[TestClass]
public class BingBangBoom
{
[TestInitialize]
public void Setup()
{
// ...
}
[TestMethod]
public void Bing()
{
// ...
}
[TestMethod]
public void Bang()
{
// ...
}
[TestMethod(PreventInitialize)]
public void Boom
{
// ...
}
}
No worries if not, I can come up with an alternative solution
Edit - RE DavidG:
It seems a shame to have this:
[TestClass]
public class BingBangBoom
{
[TestInitialize]
public void Setup()
{
// ...
}
// 10 very related methods
}
[TestClass]
public class BingBangBoom2
{
// 1 method, even though it's entirely related to BingBangBoomin'
}
I guess it is what it is.
That's not immediately obvious, but surely doable.
Assuming you have attribute like this:
public class SkipInitializeAttribute : Attribute { }
The thing you need is public property inside your test class to be injected by testing framework:
public TestContext TestContext { get; set; }
And then just branch your initialization like this:
[TestInitialize]
public void Initialize()
{
bool skipInitialize = GetType().GetMethod(TestContext.TestName)
.GetCustomAttributes<SkipInitializeAttribute>().Any();
if (!skipInitialize)
{
// Initialization code here
}
}
Working sample as self-tested solution:
using System;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject1
{
public class SkipInitializeAttribute : Attribute
{
}
[TestClass]
public class UnitTest1
{
public TestContext TestContext { get; set; }
private bool IsInitializationDone { get; set; }
[TestInitialize]
public void Initialize()
{
bool skipInitialize = GetType().GetMethod(TestContext.TestName).GetCustomAttributes<SkipInitializeAttribute>().Any();
if (!skipInitialize)
{
// Initialization code here
IsInitializationDone = true;
}
}
[TestMethod]
public void TestMethod1()
{
Assert.IsTrue(IsInitializationDone);
}
[TestMethod]
[SkipInitialize]
public void TestMethod2()
{
Assert.IsFalse(IsInitializationDone);
}
[TestMethod]
public void TestMethod3()
{
Assert.IsTrue(IsInitializationDone);
}
}
}
And results:
Starting test execution, please wait...
Passed TestMethod1
Passed TestMethod2
Passed TestMethod3
Total tests: 3. Passed: 3. Failed: 0. Skipped: 0.
Test Run Successful.
Having this general idea in mind you can play with base class / helpers etc.

Test order Microsoft.VisualStudio.TestTools.UnitTesting issue?

I have some test code that seems to be running out of the correct order.
[TestClass]
public class DirTest {
public DirTest() {
Assert.AreEqual( Directory.Exists( "testpath" ), true );
}
[TestMethod]
public void TestMethod1() {
}
[ClassInitialize]
public static void InitTest( TestContext context ) {
Directory.CreateDirectory( "testpath" );
}
}
It throws an error that the directory does not exist, shouldn't ClassInitialize run before the class constructor is called or is there something I need to do that is missing. If that is not the case is there a test case other then AssemblyInitialize that can be included in the test that is called prior to the class being constructed?
-- Edit
The real issue is here, the top is a simplification.
//RealClass.cs
public class RealClass{
public RealClass( string path ){
this._path = path;
this._InitDirectory();
}
protected string _path;
protected void _InitDirectory(){
//Something that requires read from path
File.WriteAllText( this._path + "/realData.data", "some real data that needs to be created by the class" );
}
}
//DirTest.cs
[TestClass]
public class DirTest : RealClass {
public DirTest() : base( "testpath" ) {}
[TestMethod]
public void TestMethod1() {
}
[ClassInitialize]
public static void InitTest( TestContext context ) {
Directory.CreateDirectory( "testpath" );
}
}
The unit test will fail because the directory where the path is required will die before the "ClassInitialize" method is called to create the mock directory required.
-- Edit
I have come up with a work around for this, though I would still like to know if there is another way to achieve the desired result without adding more classes, and without removing the functionality of the test. I have setup a "AssemblyInitialize" to a class that just contains that static method, and told that method to fire the static methods for "ClassInitialize". It of course fires before any constructors. Though the root of the issue is still unresolved as it is not self contained but dependent on a class function to call the class setup.
You're trying to use the approach of deriving your [TestClass] from your SUT class in order to access protected methods.
Firstly: is what you're doing really necessary? In the code you posted, there are no tests that explicitly try to access a protected member of the SUT. So, it's possible that you're making things more difficult than they need to be.
Now, if you do actually need to test a protected member in this SUT class, then have you considered creating an class that inherits from the SUT class - a class that isn't the [TestClass]? For example:
//RealClass.cs
public class RealClass{
public RealClass( string path ){
this._path = path;
this._InitDirectory();
}
protected string _path;
protected void _InitDirectory(){
//Something that requires read from path
File.WriteAllText( this._path + "/realData.data", "some real data that needs to be created by the class" );
}
}
// TestableRealClass.cs - Only used by the unit test
public class TestableRealClass: RealClass {
public TestableRealClass(string path) : base(path) { }
public string Path {
get {
return _path;
}
}
public InitDirectory() {
_InitDirectory();
}
}
//DirTest.cs
[TestClass]
public class DirTest {
[TestMethod]
public void TestMethod1() {
var testPath = #"C:\SomePath";
if (!Directory.Exists( testPath )) {
Directory.CreateDirectory( testPath );
}
var sut = new TestableRealClass(testPath);
AssertThatTheFileContainsExpectedStuff(testPath);
}
[TestMethod]
public void TestAProtectedMember() {
var testPath = #"C:\SomePath";
if (!Directory.Exists( testPath )) {
Directory.CreateDirectory( testPath );
}
var sut = new TestableRealClass(testPath);
Assert.AreEqual(testPath, sut.Path);
}
private void AssertThatTheFileContainsExpectedStuff(string path) {
// Do the assertion...
}
}
This way you don't have to worry about the order in which the text fixture will initialize, and your tests become considerably easier to understand.
update your code as follows:
[TestClass]
public class DirTest {
public DirTest() { }
[TestMethod]
public void TestMethod1() {
}
[ClassInitialize]
public static void InitTest( TestContext context ) {
if (!Directory.Exists( "testpath" )) {
Directory.CreateDirectory( "testpath" );
}
}
}

Accessing CurrentTestOutcome in ClassCleanup?

Using C# 4.0. I have a unit test where I need to create a temporary database. This is done during class initialization:
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
// Create database!
}
[ClassCleanup()]
public static void MyClassCleanup()
{
// Remove database IF CurrentTestOutcome == UnitTestOutcome.Passed
}
Q: How can I read the CurrentTestOutcome value from my ClassCleanup method?
I'd suggest that you create a static flag that you can access from your MyClassCleanup and set it during test cleanup when you get an error. Something like the following on your class:
[TestClass]
public class MyTests {
static bool _testFailed;
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
// Create database!
_testFailed = false;
}
[ClassCleanup()]
public static void MyClassCleanup()
{
if(_testFailed == false) {
// Remove database IF CurrentTestOutcome == UnitTestOutcome.Passed
}
}
[TestCleanup()]
public void MyTestCleanup() {
if (TestContext.CurrentTestOutcome != UnitTestOutcome.Passed) {
_testFailed = true;
}
}
public TestContext TestContext { get; set; }
}
I'm suggesting the above approach because my understanding is that in your class cleanup, referring to CurrentTestOutcome wouldn't really make much since. It would simply contain the state of the last test to run, not the combined outcome from all of the tests in the class.
I'm considering the following solution. Not sure if this may be considered good practice or not.
private static IList<TestContext> testResults;
public TestContext TestContext
{
get
{
return testContext;
}
set
{
testContext = value;
testResults.Add(testContext);
}
}
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
testResults = new List<TestContext>();
}
[ClassCleanup()]
public static void MyClassCleanup()
{
if (testResults.All(t => t.CurrentTestOutcome == UnitTestOutcome.Passed ||
t.CurrentTestOutcome == UnitTestOutcome.Inconclusive))
{
// Perform conditional cleanup!
}
}

Is there a way to Create nunit Setup with arguments

Is there a way to add arguments to an nunit setup method like this: public void SetUp(Point p = null) { /*code*/ }.
I tried it and got the following exception SetUp : System.Reflection.TargetParameterCountException : Parameter count mismatch
I think that your point is to avoid code duplication.
Try to extract base class with overriten method used in SetUp().
All derived class will execute tests from base class, with objects prepared in overriten OnSetUp()
[TestFixture]
public class BaseTestsClass
{
//some public/protected fields to be set in SetUp and OnSetUp
[SetUp]
public void SetUp()
{
//basic SetUp method
OnSetUp();
}
public virtual void OnSetUp()
{
}
[Test]
public void SomeTestCase()
{
//...
}
[Test]
public void SomeOtherTestCase()
{
//...
}
}
[TestFixture]
public class TestClassWithSpecificSetUp : BaseTestsClass
{
public virtual void OnSetUp()
{
//setup some fields
}
}
[TestFixture]
public class OtherTestClassWithSpecificSetUp : BaseTestsClass
{
public virtual void OnSetUp()
{
//setup some fields
}
}
Using parametrised TestFixture also can be usefull. Tests in class will be lunched per TestFixture, SetUp method also.
But remember that
Parameterized fixtures are (as you have discovered) limited by the fact that you can only use arguments that are permitted in attributes
Usage:
[TestFixture("some param", 123)]
[TestFixture("another param", 456)]
public class SomeTestsClass
{
private readonly string _firstParam;
private readonly int _secondParam;
public WhenNoFunctionCodeExpected(string firstParam, int secondParam)
{
_firstParam = firstParam;
_secondParam = secondParam;
}
[Test]
public void SomeTestCase()
{
...
}
}

Categories