Repeat a set of tests for different conditions? - c#

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

Related

Do not share static properties in tests

I have to write tests for existing code with xUnit. Here is a simplified problem I faced with:
using Xunit;
namespace XUnitTestProject1
{
public class UnitTest1
{
[Fact]
public void Test1()
{
GlobalHanler.StaticProperty = "some value";
}
[Fact]
public void Test2()
{
Assert.Null(GlobalHanler.StaticProperty);
}
}
public static class GlobalHanler
{
public static string StaticProperty;
}
}
GlobalHandler owns another object, both are static
When I run 2 tests together, Test2 fails because it can see the value that was set in Test1.
However, when I run Test2 separately, it succeeds.
My goal is to make 2 tests pass when they run together. I need somehow to reset global static property for each test separately, but I can't change the implementation of GlobalHandler
Setting StaticProperty in each test method seems not an option, because it will affect other tests running in parallel
In order to have testable code, you should first put the logic in a class that can be created as many times as needed and then use that class across your code by passing the reference.
Your production code can always use a singleton, but having no direct references to the singleton makes it testable.
Singletons and testing do not cohabit very well due to the possible side effects and unclear dependencies.
You should avoid using static. Instead of this, create a simple class and register it in your DI container as a singleton. Then you can test it easily.
Simple example:
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main()
{
var serviceProvider = new ServiceCollection()
.AddSingleton<IQueueUrlProvider, QueueUrlProvider>()
.BuildServiceProvider();
Console.WriteLine(serviceProvider.GetService<IQueueUrlProvider>().QueueUrl);
}
public interface IQueueUrlProvider
{
string QueueUrl { get; }
}
public class QueueUrlProvider : IQueueUrlProvider
{
private readonly Lazy<string> _getQueueUrlLazy;
public string QueueUrl => _getQueueUrlLazy.Value;
public QueueUrlProvider()
{
_getQueueUrlLazy = new Lazy<string>(GetQueueUrl);
}
private string GetQueueUrl()
{
// get url here
return "your queue url";
}
}
}
https://dotnetfiddle.net/JjRh4q

How can I initialize TestContext property in another class?

I am new to Selenium and I am trying to perform a data-driven test through CSV file. For this I am defining DataSource attribute in a class which contains test attributes. I am using MStest framework.
[TestClass]
public class UnitTest1:BaseDriver
{
ExcelTest sd;
private TestContext instance;
public TestContext TestContext
{
set { instance = value; }
get { return instance; }
}
public UnitTest1()
{
sd = new ExcelTest(_driver);
}
[TestInitialize]
public void Testinitialize()
{
}
[TestMethod]
[DeploymentItem("TestData.csv")]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", #"C:\Users\nidumukv\Documents\Visual Studio 2012\Projects\BMICalculator\BMICalculator\DataFiles\TestData.csv", "TestData#csv", DataAccessMethod.Sequential)]
public void DDtest_usingCSV()
{
string feet = TestContext.DataRow["feet"].ToString();
string inches = TestContext.DataRow["inches"].ToString();
string weight = TestContext.DataRow["weight in pounds"].ToString();
string BMI = TestContext.DataRow["BMI"].ToString();
sd.TestUsingCSV(feet,inches,weight,BMI);
}
[TestCleanup]
public void cleanup()
{ _driver.Quit(); }
}
BaseDriver is a class I am using to store the actual webdriver. PageElements is a class in which I have declared all the web elements.
I am trying to define the variables that are in 'DDtest_usingCSV' method in a seperate class so that the test does not become clumsy. But whenever I am defining another testcontext in another class I am getting a NullReferenceException. I have tried passing the property between classes. But I could not do it (I am still learning).
Below is the class I am trying to initialize the TestContext
public class ExcelTest:PageElements
{
public IWebDriver _driver;
public ExcelTest(IWebDriver driver):base(driver)
{
_driver = driver;
}
public void TestUsingCSV(string _feet,string _inches,string _weight,string _BMI)
{
feet.SendKeys(_feet);
inches.SendKeys(_inches);
weight.SendKeys(_weight);
compute_btn.Click();
}
}
As I could not initialize the property, I am parameterizing that method in the test class file.
And while declaring the TestContext property as mentioned below, why are we using "TestContext" as property name instead of instance??
private TestContext instance;
public TestContext TestContext
{
set { instance = value; }
get { return instance; }
}
At the time of reading values from excel, we are taking "TestContext" for accessing DataRow instead of "instance" . This question is bugging me whenever I look at it.
public void DDtest_usingCSV()
{
string feet = TestContext.DataRow["feet"].ToString();
string inches = TestContext.DataRow["inches"].ToString();
string weight = TestContext.DataRow["weight in pounds"].ToString();
string BMI = TestContext.DataRow["BMI"].ToString();
sd.TestUsingCSV(feet,inches,weight,BMI);
}
Please don't mind the length of the question. I gave a detailed explanation on my problem. Any help can be appreciated. Thanks in advance.
TestContext is set automatically by the MSTEST framework but only in the class attributed with [TestClass] and when it executes a test from this class.
In you case, just pass TestContext as a parameter in the TestUsingCSV method of the ExcelTest class.

Is there a way to set a value in one unit test that can be used by another

I have a simple question, im creating a unit test class lets say it looks like this:
namespace Tests
{
[TestClass]
public class ApiTest
{
private var x;
[TestMethod]
public testA()
{
some operactons
x = some value
}
[TestMethod]
public testB()
{
if(x == null)
test fail
}
}
Now as presented above I am interested in, is it possible to set one value (x) in Test Method A so it could be used in Test Method B?
you can do this by declaring var x as static:
private static var x;
But i wouldn't recommend to set the variable from a TestMethod. If "var x" is a variable you need in every other TestMethod (testC, testD, ...) then set it in the ClassInitialize(). This way var x is available for every TestMethod in your class ApiTest.
[TestClass]
public class ApiTest
{
private static var x;
[ClassInitialize()]
public static void InitApiTest(TestContext context)
{
some operactons
x = some value
}
[TestMethod]
public testA()
{
//Obsolete
}
[TestMethod]
public testB()
{
if(x == null)
test fail
else
...
}
}
Like what has been suggested, you probably shouldn't do it in the first place. Unit test should be independent to each other. But You can set the prerequisites of your tests in either Test initializer or Class initializer, e.g.
private int x;
[TestInitialize]
public void Init()
{
x = ...;
}
Test initializer will be executed before every test in the test class.
Use the TestInitialize attribute to run code before running each test. The method with this attribute will be run before both test a and test b.
[TestInitialize()]
public void MyTestInitialize()
{
x = someValue;
}
If you only want to do it once before all tests, do it in the constructor.
MSDN about Visual Studio unit tests

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.

Using NUnit -- how can I get currently executing test fixture and name?

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

Categories