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.
Related
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?
I have a Winforms application that is designed to integrate with external software packages. This application reads data from these packages and pushes it to our server where users log in and use our application (App).
public abstract ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
When we designed the application it was intended to do 95% of the integration work with the remaining 5% (implementation class / App2) being developed by a consultant who's familiar with the 3rd party software.
public class Implemented : ClassToImplement{
public override void DefinedMethod1(...);
public override void DefinedMethod2(...);
}
The "App" outputs a Class Library which is then referenced in the Implementation (App2). In our design we created an Abstract Class and defined the methods. The idea was that the consultant would download the repo for the implementation class and include the App as a reference. They would then write the necessary code for the methods they're implementing, compile and "voila!"
For obvious reasons I don't want to share the source project with external developers, otherwise I'd just share the full solution and use a single app, and, while I know they can see a lot with the DLL reference, it is just easier for us to control everything.
The problem comes with App: the main application algorithm needs to instantiate the implementation class and then the program runs perfectly.
in Form1.cs of App:
ClassToImplement impObj = new Implemented();
impObj.DefinedMethod1();
impObj.DefinedMethod2();
The challenge I'm having is that I cannot build "App" to output a DLL without instantiating the Class. I cannot instantiate the Implemented Class as I haven't got the code (yet).
It would be great to know how to go about achieving this sort of abstraction with a dependancy on (yet) unwritten code and also, what is the technical term for what I'm trying to do?
To make it just "work" use a Func which returns an instance of the abstract class.
In your secret repo:
//Your "App" DLL Project
public abstract class ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
public class App : Form
{
public App(Func<ClassToImplement> initiator)
{
InitializeComponent();
ClassToImplement ci = initiator.Invoke();
ci.DefinedMethod1();
ci.DefinedMethod2();
}
}
//This is in a separate project which will be your startup project internally
public class Dummy : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Dummy()));
}
}
In the repo shared with the consultant:
// In the repo which is shared with the consultant
// This will be the startup project on the build server, and when the consultant is testing.
public class Implementation : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Implementation()));
}
}
On your build server, you can pull from both the repos, and set the startup project as the one given to the consultant. But when you are testing and developing internally, you set the startup project to your version with an implementation that does nothing.
As a side note, if you think what you are doing needs to be protected from consultants who have signed a confidentiality agreement, make sure to obfuscate when you do a release.
This is a two-step process usually:
Locate and load the assembly/dll:
Assembly assembly = Assembly.LoadFrom(DLL);
Instantiate the implemented class:
Type type = assembly.GetType(FullNameOfImplemented);
AppInstance = (ClassToImplement)Activator.CreateInstance(type, parameters);
The process you are looking for is often called stubbing. In this case you've chosen to encapsulate the integration functionality in a library, not web services, but the principle is the same.
The idea was that the consultant would download the repo for the implementation class and include the App as a reference.
This sounds like you've got the dependency relationship the wrong way round. If the consultant's code references your app, then your app can't reference it - it'd be a circular dependency. Instead, factor your app something more in line with the following:
App
|
|
App.Integration.Contracts
^ ^
| |
| App.Integration.Stub
|
App.Integration
The abstract class - it could just as easily be an interface in C# - resides in the Contracts assembly. This is the only compiled dependency your application has. Then at runtime use configuration to load either the stub, or the full implementation using an IoC container. An example is Unity for which you will need its configuration API. Reference the true type to use in the configuration file and change only that to update your application to use the full functionality.
First off I think you need to implement a proper plugin system if you dont want to share your code with that other developers.
Second you should code against your interface and not against its implementation. First because you dont have it and second because you may want to switch implementations for different 3rd party software.
If you need an instance for testing or stuff, you can use a handwritten mock or an mocking framework. If you need a real instance later on (when the other developers have delivered) you can use some design pattern like factory pattern or others for the creation. Try to avoid the new keyword if you want to change implementations later on.
I recently starting fiddling around with the Telerik Test Framework ( http://www.telerik.com/teststudio/testing-framework ).
I used this to set up automated browser tests.
At first i used them in classical test project in Visual Studio and everything worked fine.
Next i wanted to be able to use the automated browser outside of Visual Studio. So i create a console application where i used the framework for my automated browser, and everything worked fine.
Next i wanted to create a MVC project where i used the framework for the automated browser, and everything stopped working.
It seems like that for some reason when the automated browser is called from a web application that the selected browser won't start up.
The actual code were the automated browser is started is the same for the web app and the console app. Just different starting points.
I also don't get any errors about the browser not starting up, i simply end up with a time out exception from the framework after i want to launch the browser.
Console code:
namespace AutomatedTests
{
class Program
{
static void Main(string[] args)
{
var telerik = new TelerikTests();
telerik.TestLanguageCoockie();
}
}
}
Web application code:
namespace AutomatedTests.Controllers
{
public class BrowserTestController : Controller
{
public ActionResult Index()
{
var telerikTests = new TelerikTests();
telerikTests.TestLanguageCoockie();
}
}
}
TelerikTests code:
namespace AutomatedTests.Tests
{
[TestClass]
public class TelerikTests : BaseTest
{
private static Settings settings;
public TelerikTests()
{
Init();
}
private Manager createMyManager
{
get
{
return new Manager(settings); // = ArtOfTest.WebAii.Core.Manager
}
}
public void Init()
{
// Get basic settings.
settings = GetSettings(); // = BaseTest.GetSettings();
// Custumize away!
settings.Web.DefaultBrowser = BrowserType.Chrome;
settings.Web.KillBrowserProcessOnClose = true;
}
[TestMethod]
public void TestLanguageCoockie()
{
var myManager = createMyManager;
myManager.Start();
myManager.LaunchNewBrowser();
// More code to perform the actual test, but with the web app approach we never get past this. The browser doesn't start and a time out exception is thrown.
}
}
}
EDIT: It turns out that i have this issue for every browser, except IE. But i do need it working for the other browsers as well.
I ended up setting up a console project + a web application. The web application contacts the console application so that it can perform all the automated browser tasks. Later it send the information back to the web app so that it can send it back to the client.
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.
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