Do long term operation only once per NUnit test run - c#

what I try to do is make a long term operation only once per all Unit tests.
OneTimeSetup is not the soltution I'm searching for :).
I want to do this:
Before starting the first test do a long time operation for example load a large file.
Start TestFixture 1
Run Test 1 (Result of step 1 must be available)
Run Test 2 (Result of step 1 must be available)
Start TestFixture 2
Run Test 1 (Result of step 1 must be available)
Run Test 2 (Result of step 1 must be available)
... and so on
Cleanup
Is this possible?
Any suggestions
Greetings Michael

You could use a separate class with a static constructor:
public static class LongTimeOperation
{
static LongTimeOperation()
{
Thread.Sleep(10000);
Resource = (++count).ToString();
}
public static string Resource { get; set; }
private static int count = 0;
}
[TestFixture]
public class TestFixture1
{
[OneTimeSetUp]
public void OneTimeSetUp()
{
resource = LongTimeOperation.Resource;
}
[Test]
public void Test1() => Assert.That(resource, Is.EqualTo("1"));
[Test]
public void Test2() => Assert.That(resource, Is.EqualTo("1"));
private string resource;
}
[TestFixture]
public class TestFixture2
{
[OneTimeSetUp]
public void OneTimeSetUp()
{
resource = LongTimeOperation.Resource;
}
[Test]
public void Test1() => Assert.That(resource, Is.EqualTo("1"));
[Test]
public void Test2() => Assert.That(resource, Is.EqualTo("1"));
private string resource;
}

Related

How to create an automation test for a workflow

I am working on a workflow project that has 19 scenarios for testing the whole system and 34 steps.
So, my question is, how can I create an automation test for it?
My current approach is:
Create an integrated test per each scenario, and then create the main system test to run all integrated tests.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace Project1
{
// Unit tests
public class UnitTest_step1
{
public void RunTest() { }
}
public class UnitTest_step2
{
public void RunTest() { }
}
public class UnitTest_step3
{
public void RunTest() { }
}
public class UnitTest_step4
{
public void RunTest() { }
}
// End of unit tests
public class IntegrationTests
{
public void IntegrationTest1()
{
UnitTest_step1.RunTest();
UnitTest_step2.RunTest();
UnitTest_step4.RunTest();
}
public void IntegrationTest2()
{
UnitTest_step1.RunTest();
UnitTest_step2.RunTest();
UnitTest_step3.RunTest();
UnitTest_step4.RunTest();
}
public void IntegrationTest3()
{
UnitTest_step1.RunTest();
UnitTest_step4.RunTest();
}
}
[TestClass]
public class SystemTests
{
[TestMethod]
public void Scenario1()
{
IntegrationTests.IntegrationTest1()
}
[TestMethod]
public void Scenario2()
{
IntegrationTests.IntegrationTest2();
}
[TestMethod]
public void Scenario3()
{
IntegrationTests.IntegrationTest3();
}
[TestMethod]
public void ScenarioN()
{
IntegrationTests.IntegrationTestN();
}
}
}
Best Regards.
Well, in my opinion, the information provided in your question is very abstract and the question is a bit too broad.
The answer depends on how your workflow engine is implemented and what are your system requirements.
Requirements and implementation details are what defines your approach to testing.
I would start with clarifying what kind of steps you have, is there any data context is passed,
what side effects these steps produce (writes data to database, sends events, call other system APIs, etc.),
do steps depend on each other and so on.
Another question is how do you need to assert the results, after each step or after scenario?
The system should be testable and normally, each step should be covered with unit tests.
So, suggested hypothetical approach is to cover each step with isolated unit tests
and scenarios with integration tests.
I came up with a simple example just to illustrate one of the general approaches.
For simplicity, I assume that steps have little or no data context and can be reordered.
namespace Workflow.Test
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
[TestClass]
public class SystemTests
{
[TestMethod]
public void Scenario1()
{
new Workflow().Run(new Scenario1());
}
[TestMethod]
public void Scenario2()
{
new Workflow().Run(new Scenario2());
}
// The advantage of explicit steps declaration is test readability.
// Declarative approach also enables the further possibility of test generation!
[TestMethod]
public void MoreExplicitAndDeclarative()
{
new Workflow().Run(new List<Type>
{
typeof(Step1),
typeof(Step2),
typeof(Step3),
});
}
// Step instantiation may be needed if you want to parameterize some steps.
[TestMethod]
[DataRow("Custom step")]
[DataRow("Another step")]
public void MoreExplicitParameterizedScenario(string customName)
{
new Workflow().Run(new List<IRunnable>{
new Step1(),
new Step3(customName)
});
}
}
[TestClass]
public class StepsUnitTests
{
[TestMethod]
public void Step1DoesWhatWeWant()
{
// Mock dependencies
new Step1().Run();
// Assert results
}
}
#region Workflow Engine Example
public interface IRunnable
{
void Run();
}
public class Workflow
{
public void Run(Scenario scenario)
{
Run(CreateSteps(scenario.GetStepTypes()));
}
public void Run(IEnumerable<Type> stepTypes)
{
Run(CreateSteps(stepTypes));
}
public void Run(List<IRunnable> steps)
{
steps.ForEach(step => step.Run());
}
private List<IRunnable> CreateSteps(IEnumerable<Type> stepTypes)
{
var steps = new List<IRunnable>();
foreach (var stepType in stepTypes)
{
steps.Add(CreateStep(stepType));
}
return steps;
}
private IRunnable CreateStep(Type stepType)
=> (IRunnable) Activator.CreateInstance(stepType);
}
#endregion
// Step structure can differ according to system requirements.
// We may add data context and link steps into pipeline if needed.
#region Steps
public abstract class Step : IRunnable
{
private readonly string _stepName;
protected Step(string name)
{
_stepName = name;
}
public void Run()
{
Console.WriteLine($"{_stepName} in action.");
Invoke();
}
public abstract void Invoke();
}
public class Step1 : Step
{
public Step1() : base(nameof(Step1))
{
}
public override void Invoke()
{
// do work
Console.WriteLine($"Step1 invoked.");
}
}
public class Step2 : Step
{
public Step2() : base(nameof(Step2))
{
}
public override void Invoke()
{
// do work
Console.WriteLine($"Step2 invoked.");
}
}
public class Step3 : Step
{
public Step3(string customName) : base(customName)
{
}
public Step3() : this(nameof(Step3))
{
}
public override void Invoke()
{
// do work
Console.WriteLine($"Step3 invoked.");
}
}
public class Step4 : Step
{
public Step4() : base(nameof(Step4))
{
}
public override void Invoke()
{
// do work
Console.WriteLine($"Step4 invoked.");
}
}
#endregion
// Scenarios should be as declarative as possible.
// Let's say the scenario is just specification of what steps (step Type)
// and in what order should be executed (List as a non-unique ordered collection).
#region Scenarios
public abstract class Scenario
{
public abstract List<Type> GetStepTypes();
}
public class Scenario1 : Scenario
{
public override List<Type> GetStepTypes()
=> new List<Type>
{
typeof(Step1),
typeof(Step2),
typeof(Step3)
};
}
public class Scenario2 : Scenario
{
public override List<Type> GetStepTypes()
=> new List<Type>
{
typeof(Step1),
typeof(Step2),
typeof(Step4)
};
}
#endregion
}

Can setup and teardown be called for each of the Test Cases?

[Setup]
public void RunBeforeAnyTest()
{
}
[TearDown]
public void RunAfterEveryTest()
{
}
[Test]
public void Test1()
{
}
[TestCase("case1")]
[Testcase("case2")]
public void Test2()
{
}
In above example, the Setup and TearDown gets executed before and after Test1 and Test2. But I want it to execute before and after individual test case in Test2. Is it possible with nunit framework? How can I achieve this?
After correcting for some typos:
[TestFixture]
public class Class1
{
[SetUp]
public void RunBeforeAnyTest()
{
Console.WriteLine("RunBeforeAnyTest");
}
[TearDown]
public void RunAfterEveryTest()
{
Console.WriteLine("RunAfterEveryTest");
}
[Test]
public void Test1()
{
Console.WriteLine("Test1()");
}
[TestCase("case1")]
[TestCase("case2")]
public void Test2(string param)
{
Console.WriteLine($"Test2({param})");
}
}
The output is:
RunBeforeAnyTest
Test1()
RunAfterEveryTest
RunBeforeAnyTest
Test2(case1)
RunAfterEveryTest
RunBeforeAnyTest
Test2(case2)
RunAfterEveryTest
Isn't that what you hoped?

NUnit: how to invoke Test from another class with Parallelizable

When trying to invoke a Test from a different class from where it is implemented, it does not execute the Parallelizable attribute, instead, it only executes the methods sequentially ( Alltest_2() and Alltest_1() ). Is there any way to invoke them so that they are executed in parallel?
Here's a code sample:
public class AO_Alarms_4 : AO_Alarms_3
{
[SetUp]
public void DefaultSetUp(){ }
[Test]
public void Alltest_Clases()
{
Alltest_2();
Alltest_1();
}
[TearDown]
public void DefaultTearDown() { }
}
[TestFixture]
[Parallelizable]
public class AO_Alarms_3 : AO_Alarms_2
{
public WebDriverFactory driver = new WebDriverFactory(Utils.Browser);
[SetUp]
public void login_2()
{
//code
}
[Test]
[Parallelizable]
public void Alltest_2()
{
test_2();
}
public void test_2()
{
//code
}
[TearDown]
public void teardown_2()
{
//code
}
}
[TestFixture]
[Parallelizable]
public class AO_Alarms_2
{
public WebDriverFactory driver = new WebDriverFactory(Utils.Browser);
[SetUp]
public void login_1()
{
//code
}
[Test]
[Parallelizable]
public void Alltest_1()
{
test1_1();
test1_2();
}
[Test]
public void test1_1()
{
//code
}
[Test]
public void test1_2()
{
//code
}
[TearDown]
public void teardown_1()
{
//code
}
}
You can't simply call tests yourself and expect to get any of the normal NUnit behavior around tests. For example, NUnit knows what to do when it calls a test with [Parallelizable] on it - and what it does is fairly complicated. Your own call is simply calling the method you wrote.
There is nothing to stop you from calling common methods within a given test, but the tests themselves have to be invoked by NUnit.
If you can rephrase or ask another question about what you are actually trying to accomplish here, we can probably give you some advice about alternatives.

How do I Execute Code after a Test failed

I am Creating Unit Tests for a Library. This Library Connects to a Datasource and then I am doing some testing Stuff afterwards the Datasource will be disconnected.
If one of the Tests fails, the Method is Terminated and I dont get to execute the Disconnection Function.
Here's a Sample to understande the above description:
[TestMethod]
public void Test()
{
var datasourceObject = new DatasourceObject("location-string");
datasourceObject.Connect();
// Do some Stuff with Asserts
datasourceObject.Disconnect(); // must be executed
}
Is There any Bestpractice to achieve that?
If you use resource in other tests, then move it to class fields and use [TestInitialize] and [TestCleanup] to get and free that resource:
private Foo datasourceObject;
[TestInitialize]
public void TestInitialize()
{
this.datasourceObject = new DatasourceObject("location-string");
this.datasourceObject.Connect();
}
[TestMethod]
public void Test()
{
// Do some Stuff with Asserts
}
[TestCleanup]
public void TestCleanup()
{
this.datasourceObject.Disconnect();
}
If you use resource in this test only, then use either try..finally
[TestMethod]
public void Test()
{
try
{
var datasourceObject = new DatasourceObject("location-string");
datasourceObject.Connect();
// Do some Stuff with Asserts
}
finally
{
datasourceObject.Disconnect(); // must be executed
}
}
Or using statement if resource is disposable:
[TestMethod]
public void Test()
{
using(var datasourceObject = new DatasourceObject("location-string"))
{
datasourceObject.Connect();
// Do some Stuff with Asserts
}
}

How to Run c# Multiple Selenium Unit Test with one driver instance?

i have a problem running Multiple C# Selenium Unit Test tests with one driver instance.
Please find my class as below.
Folder : Com.Main.Web.Selenium
SeleniumTestInitialize.cs is the main class which contains the driver.
[DeploymentItem(#"Resources\IEDriverServer.exe")]
public class SeleniumTestInitialize
{
public TestContext TestContext
{
get { return testContextInstance; }
set { testContextInstance = value; }
}
private TestContext testContextInstance;
public bool SeleniumExecutionTerminateFlag=false;
public SeleniumTestInitialize seleniumTestInitalize;
public FindWebDriverElement findWebDriverElement;
public JavaScriptCalls javaScriptCalls;
public OperateOnWebDriverElement operateOnWebDriverElement;
**public RemoteWebDriver driver;**
// how to use this driver object across multiple unit test classes
public string baseURL;
public void SeleniumSetup()
{
try
{
Console.WriteLine("Starting Driver...........");
seleniumTestInitalize = new SeleniumTestInitialize();
var options = new InternetExplorerOptions
{
IntroduceInstabilityByIgnoringProtectedModeSettings = true,
//ForceCreateProcessApi=true
EnableNativeEvents = false,
RequireWindowFocus = false,
IgnoreZoomLevel = true
};
driver = new InternetExplorerDriver(TestContext.DeploymentDirectory, options);
javaScriptCalls = new JavaScriptCalls(driver);
findWebDriverElement = new FindWebDriverElement(javaScriptCalls);
operateOnWebDriverElement = new OperateOnWebDriverElement(findWebDriverElement);
GoToSite(ConfigParameters.WEB_APPLICATION_URL);
driver.Manage().Window.Maximize();
}
catch (Exception e)
{
log.Debug("Error Starting Web Driver...........");
Console.WriteLine(e.StackTrace);
}
}
public bool SeleniumInitalizeCheck()
{
if (seleniumTestInitalize != null)
return true;
else
return false;
}
public void SeleniumQuit()
{
Console.WriteLine("Quitting Driver...........");
try
{
if (driver != null)
{
driver.Quit();
}
log.Info("Closing Web Driver...........");
ProcessMgn.killProcessByNames("IEDriverServer");//Make sure the process is killed
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
}
public void GoToSite(string urlToOpen)
{
driver.Navigate().GoToUrl(urlToOpen);
}
}
Folder com.main.tests
Test01.cs
[TestClass]
public class Test01 : SeleniumTestInitialize
{
[TestInitialize]
public void Setup()
{
SeleniumExecutionTerminateFlag = false;
if (!SeleniumInitalizeCheck())
{
SeleniumSetup();
}
}
[TestCleanup]
public void TearDown()
{
if (SeleniumExecutionTerminateFlag)
{
SeleniumQuit();
}
}
[TestMethod]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.TestCase", "http://tfsserver:8080/tfs/PoL;project", "1320", DataAccessMethod.Sequential)]
public void UCP002_M1()
{
var userName = this.TestContext.DataRow["UserName"].ToString();
var passWord = this.TestContext.DataRow["PassWord"].ToString();
//use the local host adress for your project here->
baseURL = this.TestContext.DataRow["URL"].ToString();
driver.Navigate().GoToUrl(baseURL);
//driver.FindElement(By.XPath("//html/body/div[2]/div/a/p/desc")).Click();
//driver.FindElement(By.Id("registerLink")).Click();
driver.FindElement(By.Id("ctl00_LoginTextBox")).Clear();
driver.FindElement(By.Id("ctl00_LoginTextBox")).SendKeys(userName);
driver.FindElement(By.Id("ctl00_PasswordTextbox")).Clear();
driver.FindElement(By.Id("ctl00_PasswordTextbox")).SendKeys(passWord);
driver.FindElement(By.Id("ctl00_LogInButton")).Click();
}
}
Test02.cs
[TestClass]
public class Test02 : SeleniumTestInitialize
{
[TestInitialize]
public void Setup()
{
SeleniumExecutionTerminateFlag = false;
if (!SeleniumInitalizeCheck())
{
SeleniumSetup();
}
}
[TestCleanup]
public void TearDown()
{
if (SeleniumExecutionTerminateFlag)
{
SeleniumQuit();
}
}
[TestMethod]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.TestCase", "http://tfsserver:8080/tfs/PoL;project", "1320", DataAccessMethod.Sequential)]
public void Test02()
{
//some test script
}
}
I have created an ordered test and prioritized the tests in the order of execution . But it is invoking two instances of the driver that means two times the browser.
My question is to How to share a single driver object across all selenium unit tests ?? create at the start and close the driver at the end.
Thanks.
HI If you are using using NUnit.Framework;
The code Execution plan is like below.
For First Test Case
[TestFixtureSetup] ---->For each test case this will work so here we can
initialize the driver instance.
[TestMethod] ----->test method will goes here
[TearDown] -----> clean up code
**For Second Test Case**
[TestFixtureSetup]
[TestMethod]
[TearDown]
If you have to run both test case in one browser instance
Dont close the driver inside TearDown.
AND INITIALIZE THE DRIVER UNDER TextFixtureSetup
[TestFixture()]
public class TestClass
{
[TestFixtureSetUp]
public void Init()
{
Driver.initialize(new InternetExplorerDriver());
}
[TearDown]
public void Close()
{
//dont do any driver.close()
}
[TestMethod]
public void TestCase001()
{
//your code goes here
}
[TestMethod]
public void TestCase002()
{
//your code goes here
}
You can take a look on this thread, where I answered how I did it: How to run multiple test methods in same browser instance without closing it (C#, SeleniumWebDriverz NUnit)?
Basically, I used:
using Microsoft.VisualStudio.TestTools.UnitTesting;
Instead of:
using NUnit.Framework;
So now I have next hierarchy:
[TestFixture]
[TestFixtureSetup] // this is where I initialize my WebDriver " new FirefoxDriver(); "
[Test] //first test
[Test] //second test
[Test] //third test
[TestFixtureTearDown] // this is where I close my driver
With this changes, my browser will open only once for TestFixture (or TestClass if you use "using Microsoft.VisualStudio.TestTools.UnitTesting;") and all [Test]-s from that fixture will run in that same browser instance. After all tests are done, browser will close.
Hope this will help someone else in future. Ask me if you need additional help.
I used NUnit Framework:
using NUnit.Framework;
I then set up my WebDriver initialisation, test and teardown like this:
[TestFixture()]
class NUnitSeleniumTests
{
[OneTimeSetUp]
public void Init()
{
driverIE = new InternetExplorerDriver(ConfigurationManager.AppSettings["IEDriver"]);
driverIE.Manage().Window.Maximize();
// other setup logic
}
[Test]
public void TestMethod1()
{
// Test logic
}
[Test]
public void TestMethod2()
{
// Test logic
}
...
...
...
[Test]
public void TestMethodN()
{
// Test logic
}
[OneTimeTearDown]
public void Close()
{
driverIE.Close();
}
}
When I Run All tests, the WebDriver driverIE is initialised. All tests then execute in that WebDriver instance before the WebDriver instance is closed at the end of the test run.
The tests execute in alphabetical order by default; each test can also execute in isolation.

Categories

Resources