I have an issue in where my [AssemblyCleanup] method is not being called.
I'm currently building out an automation framework and would like some API calls done before and after my tests. I've since found the assembly initialize/cleanup methods, and they would work perfect for what I need to do. But I am unable to to get the [AssemblyCleanup] method to run.
I have a base class that my tests inherent from, and that's where I'd like the [AssemblyCleanup] method to be placed.
My class.
[TestClass]
public class TestBaseChrome: WebDriver
{
public TestContext TestContext { get; set; }
[TestInitialize]
public void Initialize()
{
//Do Stuff Here for tests
}
[TestCleanup]
public void Cleanup()
{
//used for end of test reporting
}
[AssemblyCleanup]
public static void EndOfSuiteActions()
{
//Stuff here when whole test suite finished
}
}
I've seen the examples here and here and show that the [AssemblyCleanup] needs to be in a class with the [TestClass] attribute. If I place the [AssemblyCleanup] in a class with actual tests, it works as intended. But I'd like all my before tests/after tests in once place.
Any advice would be appreciated.
I believe I've found the answer to my own question.
If a [TestClass] inherits from a base class that is in a different assembly of the derived class, the base class [AssemblyInitialize] and [AssemblyCleanup] methods are not executed.
Source
So as my automation tests are in two projects in the solution (one to handle the framework and one to handle the tests) and as the base class is in the framework, but the tests are the other project. I encounter the issue in the link.
Related
I have domain classes that reference System.Diagnostics.Activity.Current.Id in my web api. It uses this value as a correlation Id once the object is serialized and stored in Cosmos. I have no issue getting this value when making calls into the API. However if I try to reference this value in my domain unit tests, the System.Diagnostics.Activity.Current is null. I have tried setting it in my unit test functions but it is still always null in my domain.
System.Diagnostics.Activity.Current = new System.Diagnostics.Activity("MyUnitTests");
I know System.Diagnostics.Activity.Current is driven from the current HttpContext but there also is no current http context in my domain unit tests. How can I make this work with my unit tests?
Example:
Domain Class
public class Company
{
public int CompanyId { get; private set; }
public string Name { get; private set; }
public string CorrelationId { get { return System.Diagnostics.Activity.Current.Id; } }
}
Unit Test
[TestMethod]
public void MyTest()
{
Company c = new Company();
Assert.AreNotEqual(string.Empty, c.CorrelationId);
}
This unit test throws a null reference exception because System.Diagnostics.Activity.Current is null.
I agree that using System.Diagnostics.Activity in a domain class is a code smell.
But I had a similar issue with my unit test. The tested business-logic code uses Activity.Current.AddBaggage:
Activity.Current.AddBaggage("CustomerRef","SomeCustomerReference");
Because only the logic is tested, no HttpRequest is involved and Activity.Current is NULL.
So I extended my unit test with the following base class (example is for XUnit):
public class BaseTest : IDisposable
{
private Activity unitTestActivity;
protected BaseTest()
{
unitTestActivity = new Activity("UnitTest").Start();
}
public void Dispose()
{
unitTestActivity.Stop();
}
}
This is a design issue around mixing concerns and is a possible code smell.
Current code is tightly coupled to run time concerns that are not present when unit testing in isolation.
You'll most likely need to run an integration test where actual requests are made with a valid context.
Assigning the id via a service abstraction would help loosen the coupling to run time concerns.
And remove the need to unit unit test a simple domain POCO used to store run time data.
I'm trying to use NUnit TestAttributes to create and delete a RestSharp RestClient
https://github.com/nunit/docs/wiki/TestFixture-Attribute
using NUnit.Framework;
using RestSharp;
namespace Sanitized.Sanitized.Steps
{
[TestFixture]
public class SetupAndTeardown
{
public RestClient restClient;
[SetUp]
public void Init()
{
restClient = new RestClient();
}
[TearDown]
public void Cleanup()
{
restClient = null;
}
}
}
But, I get the error Object reference not set to an instance of an object. when trying to use this in another class i.e. with my automated steps.
I don't understand this, as I thought code that's in the [SetUp] [Teardown] attributes are called at the beginning and end of the test respectively.
You created a TestFixture, which is a class that contains tests. If the fixture had any tests, then NUnit would run them and would also run the setup before each test and the teardown after each test. Since you have no tests, that isn't happening. NUnit recognizes the fixture but finds nothing to run there.
You say that you have a problem when you "use" this fixture in another class. Test fixtures are not intended to be "used" by other code. Rather, they are run by NUnit.
For a better answer about how to do what you are trying to do, we first need to know what you are trying to do. When do you want the "setup" and "teardown" to run? How often should they run? Depending on those things, I can update this answer.
Replying further to your comment... If your tests are in another class, then that class is your test fixture. Is there a reason you don't want it to be the fixture?
Posting here as my googling and searching stackoverflow hasn't given me quite what I am looking for. So, hopefully someone here can point me in the right direction or give me some pointers on how to solve my issue.
Preface: I have been teaching myself C#/.net for a little over a year now and still consider myself a novice. But in that time I have gone from a manual software tester to getting myself my first job as an Automation Engineer.
I've currently built a framework using Selenium Webdriver and the page object model framework. And the issue I have is currently my framework ideally only allows for one browser at a time. I could have different browsers being used at the same time, but i'd have to have the multiple versions of the test too.
Below is an example of how my framework is currently. As I'd imagine this would help.
public class WebDriver
{
public static IwebDriver driver;
}
Then this is inherited by my TestBase class, which is attached to each test
public class TestBase: WebDriver
{
public TestContext TestContext { get; set; }
[TestInitialize]
public void Initialize()
{
Driver = new ChromeDriver();
}
[TestCleanup]
public void Cleanup()
{
//Company specific cleanup logic
//Reporting Etc.
Driver.Quit();
}
}
This base class is then inherited by each test class; seen below.
[TestClass]
public class LoginTests : TestBase
{
[TestMethod]
public void SuccessfulLogin()
{
LoginPage login = new LoginPage();
login.NavigateToLogInPage();
HomePage homePage = login.LoginWithCorrectDetails();
homePage.LogoutFromHomePage();
}
}
What I was planning on doing was having a "Testbase" class for each browser (Chrome, firefox, IE) and would then have a version of each test, that would inherent a browser.
So, in the example below there would be
SuccessfulLogin: Chrome
SuccessfulLogin: FireFox
SuccessfulLogin: IE
While this would would, (I did a short test), it's far from ideal and I can imagine will cause various issues later on down the line.
What I'm looking for is help/direction in which I only have one version of my test and my framework is intelligent enough to run it on all browsers.
I've only started to work with specflow and i know it's bindings are global for the assembly. Anyways, i couldn't find the solution or workaround for my problem:
I use abstract class for my UI tests, such as
public abstract class UITestBase<T>
where T : FeatureContext, new()
{
private static readonly object SyncObject = new object();
private static AutoTestSettings settings;
private IWebDriver webDriver;
private IBrowserFactory browserFactory;
private Container container;
protected static T Context;
[BeforeScenario]
public virtual void BeforeScenario()
{
BuildConfiguration();
var driverPool = container.GetInstance<IWebDriverPool>();
webDriver = driverPool.GetDriver(settings.BrowserType);
browserFactory = container.GetInstance<IBrowserFactory>();
Context = new T
{
Browser = browserFactory.Create(webDriver, settings.WebsiteUrl, settings.BrowserType),
Container = container
};
}
[AfterScenario]
public virtual void AfterScenario()
{
webDriver.Dispose();
}
}
I have few FeatureSteps files, one for each page/feature. E.g LoginFeature and PurchaseFeature. Each FeatureSteps class extends UITestBase and has [Binding] attribute.
Whenever I run scenario for LoginFeature it seems to hook on BeforeScenario for PurchaseFeatureSteps as well. At least thats what Debug.WriteLine(this.GetType().Name) says.
It causes that each scenario opens as many browsers as there are inheritors of UITestBase. Although tests are running fine it looks sorta ugly and feels wrong.
Did anyone face such problem? How do I fix it?
As you noted, bindings are global in specflow. Also as you have discovered bindings in a base class are run once for each inheritor of that class. Don't place bindings into base classes, instead place them in a separate class specifically for this purpose, then Specflow will find them and run them. If you need to initialise objects for your scenarios to use, then I find its better to pass those objects through specflow's prescribed ways of sharing data between bindings. I have outlined an approach in this answer. My preference is for using context injection.
If you have some setup which is specific to particular features or scenarios, then the bindings can be scoped so that they only run for particular features or scenarions
I'm trying to test my service using ninject and an unit test project with visual studio 2012. My inject works ok on my controllers, but when I try to do the same in the unit test class I get an Exception.
System.NullReferenceException: Object reference not set to an instance of an object.
namespace Trex.UnitTests
{
[TestClass]
public class GiftServiceTests
{
private IGiftService _giftService;
public void GiftServiceTest(IGiftService giftService)
{
_giftService = giftService;
}
[TestMethod]
public void AddGift()
{
var list = _gift.FindAll(); <--- this line throw an exception
}
}
}
I think there is something wrong with the injection but I dont get it.
It looks to me like a typo of _giftService. In addition, attribute [TestInitialize] needs to be used in your constructor.
Try the following code by placing the correct service name _giftService - that your code is injecting instead:
var list = __giftService.FindAll();
Edit: Unit testing should be done without Ninject. Just create an instance of the object under test and inject a mock for every dependency manually.
Here is a sample with [TestInitialize]:
The unit test must have a default constructor:
[TestClass]
public class TestControllersHomeController
{
private HomeController _sut;
[TestInitialize]
public void MyTestInitialize()
{
var kernel = NinjectWebCommon.CreatePublicKernel();
_sut = kernel.Resolve<HomeController>();
}
[TestMethod]
public void TestIndex()
{
var result = _sut.Index();
Assert.IsNotNull(result);
}
}
The only way dependency injection is able to call your constructor and fill it with a parameter that has a value is if the dependency injection kernel is the one that instantiates your class.
In your case, MSTest is instantiating your test class, so Ninject does not have a chance to call your constructor.
To be honest, you are going about this the wrong way. You will battle MSTest if you pursue this further to try to get Ninject (or any other DI framework) to instantiate your test classes.
I would recommend you use 'new' to instantiate the class under test (_giftService = new GiftService();). If that class has dependencies in its constructor, use a mocking framework to pass in mocked version of those dependencies. This way you isolate your unit tests to only the functionality of the class under test.
_gift is null. Your variable is _giftService. You also should use the [TestInitialize] attribute for your constructor.
Extra tip:
You shouldn't create any dependencies in your unit test. So the giftService which you want to use should be a mock or a stub.