BeforeScenario and AfterScenario hooks not working in specflow - selenium

I have the following code in my SeleniumSteps.cs code
I am trying to get the AfterScenario to fire on debugging these tests
using PrivateDomain;
using Machine.Specifications;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using TechTalk.SpecFlow;
namespace Functional.Steps
{
public class SeleniumSteps : PrivateDomain.Steps.SeleniumSteps
{
#region Hooks
[BeforeScenario]
public void Before()
{
// before
}
[AfterTestRun, Scope(Tag = null)]
public new static void AfterTestRun()
{
// after testrun
}
[AfterScenario]
public void AfterScenarioErrorScreenshot()
{
// after scenario
}
#endregion
}
}
using OpenQA.Selenium;
using TechTalk.SpecFlow;
namespace PrivateDomain.Steps
{
[Binding]
[Scope(Tag = "Selenium")]
public class SeleniumSteps
{
protected static IWebDriver webDriver;
public SeleniumSteps();
public virtual IWebDriver WebDriver { get; }
[AfterTestRun]
[Scope(Tag = null)]
public static void AfterTestRun();
[AfterScenarioAttribute(new[] { })]
public virtual void AfterScenario();
}
}
My feature file looks like this:
(Details removed)
#Customer_Portal
Feature: Account Management - Registration
In order to create an account
As a customer
I want to register my details with the application
Scenario: Register
# Registration Form
When I navigate to "/Customer/Account/Register"
// more code...
Scenario: Required Fields
// more code...
Scenario: Invalid Contact Details
// more code...
Scenario: Insufficient Password Strength
// more code...
Scenario: Password Mismatch
// more code...
Scenario: Already Registered
// more code...
Scenario: Invalid Activation
// more code...
Scenario: Already Activated
// more code...
When I debug a test, I can see the debugger hitting the AfterTestRun portion.
However, neither the BeforeScenario or the AfterScenario are being exercised.
Can someone tell me what I'm doing wrong?

First, as Sandesh noted in his answer, you are missing [Binding] attribute for your SeleniumSteps subclass. It's not enough to have [Binding] only in base class, you must apply it to every class where are your hook methods or step definitions (bindings), because that is the way how specflow is searching for hooks and bindings under the hood. It is like scope identifier. If you miss to place [Binding] attribute to class, specflow will not search for potential hook methods or bindings in that class. Link on documentation: https://specflow.org/documentation/Hooks/
This link can be useful also. Check answer given by RunOfTheShipe: Specflow test step inheritance causes "Ambiguous step definitions"

You have missed [Binding] attribute in your SeleniumSteps
namespace Functional.Steps
{
[Binding]
public class SeleniumSteps : PrivateDomain.Steps.SeleniumSteps
{
#region Hooks
[BeforeScenario]
public void Before()
{
// before
}
}
}

Related

Why does 'InputField' not contain a definition for 'text'?

I'm currently working on a Unity project for a college assignment, and I'm currently trying to connect a login/registration through PlayFab into a teammate's main menu for the game.
I've connected the PlayFabManager.cs script to the Input Fields for the email and password in the Unity editor, and something about my InputFields.cs file is preventing me from making any more progress.
I had to change the passwordInput and emailInput variables to TMP_InputField variables to achieve this, but now I am getting a compilation error in my project that says the following:
Assets\Scripts\InputField.cs(13,24): error CS1061: 'InputField' does not contain a definition for 'text' and no accessible extension method 'text' accepting a first argument of type 'InputField' could be found (are you missing a using directive or an assembly reference?)
Most places I look have people not including the "using UnityEngine.UI;" header at the top of the file, but that's included in my InputField.cs file.
Here's the code for my InputField.cs file:
using UnityEngine;
using System.Collections;
using UnityEngine.UI; // Required when Using UI elements.
public class InputField : MonoBehaviour
{
public InputField mainInputField;
public void Start()
{
mainInputField.text = "Enter text here...";
}
}
Here's the code for my PlayFabManager.cs file:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PlayFab;
using PlayFab.ClientModels;
using Newtonsoft.Json;
using UnityEngine.UI;
using TMPro; // Needed for login input fields
public class PlayFabManager : MonoBehaviour
{
[Header("UI)")]
public Text messageText;
public TMP_InputField emailInput;
public TMP_InputField passwordInput;
// Register/Login/ResetPassword
public void RegisterButton() {
var request = new RegisterPlayFabUserRequest {
Email = emailInput.text,
Password = passwordInput.text,
RequireBothUsernameAndEmail = false
};
PlayFabClientAPI.RegisterPlayFabUser(request, OnRegisterSuccess, OnError);
}
void OnRegisterSuccess(RegisterPlayFabUserResult result) {
messageText.text = "Registered and Logged in";
}
public void LoginButton() {
}
// Start is called before the first frame update
void Start() {
Login();
}
// Update is called once per frame
void Login() {
var request = new LoginWithCustomIDRequest {
CustomId = SystemInfo.deviceUniqueIdentifier,
CreateAccount = true
};
PlayFabClientAPI.LoginWithCustomID(request, OnSuccess, OnError);
}
void OnSuccess(LoginResult result) {
Debug.Log("Successful login/account create.");
}
void OnError(PlayFabError error) {
Debug.Log("Error while loggin in/creating account.");
Debug.Log(error.GenerateErrorReport());
}
}
I would just remove the InputField.cs class as it fixes my errors, but it changes the functionality of the following code that my teammate has contributed:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class MenuControl : MonoBehaviour
{
public string newGameLevel;
public void NewUser() {
SceneManager.LoadScene(newGameLevel);
}
public void ExitButton() {
Application.Quit();
}
}
Any help would be much appreciated!
Wanted to provide the solution in case this happens to anyone in the future:
I solved the problem by changing the
public InputField mainInputField;
into an input variable that could receive the TMP_Imput like so: public TMPro.TMP_InputField mainInputField;

Why WebApplicationFactory is saving state from previous builds?

I will try to show my problem with a sample code easier to understand.
I have used WebApplicationFactory to develop my acceptance tests. Let's say that I have the typical minimal Program.cs with the following line to register one of my modules:
builder.Services.RegisterModule<StartupRegistrationModule>(builder.Configuration, builder.Environment);
And this module is declared like this:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
One of my tests file is like this:
public sealed class MyTests : AcceptanceTestBase
{
[Fact]
public void Test1()
{
// arrange
// act
// assert
}
[Fact]
public void Test2()
{
// arrange
// act
// assert
}
[Fact]
public void Test3()
{
// arrange
// act
// assert
}
}
And AcceptanceTestBase is:
public abstract class AcceptanceTestBase : IDisposable
{
protected HttpClient _httpClient;
protected WebApplicationFactory<Program> _webApplicationFactory;
public AcceptanceTestBase()
{
_webApplicationFactory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
// ... Configure test services
});
_httpClient = _webApplicationFactory.CreateClient();
}
public void Dispose()
{
_httpClient.Dispose();
_webApplicationFactory.Dispose();
}
}
If I try to execute all these tests my tests will fail in the second test run because the WebApplicationFactory is trying to build again the Application but it already has the key in the dictionary and it will fail. See the image for more understanding on the problem.
So my question is, how can I build the application in different scopes to do not share this dictionary state?
Thanks :)
Update:
The real static dictionary is saved behind this nuget package that keeps the track of all my circuit breaker policies state. I do not actually need even the HttpClients for my tests but did not find a way to remove them and not load this. I tried removing all the HttpClients to see if it also removes their dependencies, but it does not seem to make the trick.
It is because you are using:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
/// .. static here
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
The static Dictionary is shared over all your tests because they run in the same process.
Each test starts a new (Test-)WebHost but the dictionary remains untouched.
My proposal is to not use statics anywhere in DI context to prevent such hidden traps.
I don't know the purpose of your Dictionary here but maybe you can extract this to a singleton registration which you can replace in your (Test.)WebHost on each new test / startup?

Instantiating a class the parameter passed to it's constructor shows A field initializer cannot reference the non static field

I have started creating a framework in Selenium Webdriver in C#. I have a base class and a HomePage class. HomePage inherits the base class.
When I instantiate the HomePage class I am getting the error:
A field initializer cannot reference the non static field, method or property autobot_automation.Base.BasePageDriver.get
I have declared the driver variable in the base class and initialised it in the constructor. I do not know why the compiler is showing the error.
My Base Class is:
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using autobot_automation.Pages.HomePage;
using autobot_automation.Pages.Base;
namespace autobot_automation.Base
{
public class BasePage
{
public IWebDriver Driver { get; set; }
public BasePage(IWebDriver driver)
{
Driver = driver;
PageFactory.InitElements(Driver, this);
}
public void GoToURL(string url)
{
Driver.Navigate().GoToUrl(url);
}
#region Page Objects
public HomePage homepage = new HomePage(Driver);
#endregion
}
}
My HomePage Class is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using autobot_automation.Pages;
using autobot_automation.Base;
namespace autobot_automation.Pages.HomePage
{
public class HomePage : BasePage
{
//private IWebDriver Driver { get; set; }
public HomePage(IWebDriver driver) : base(driver)
{
//Driver = driver;
//PageFactory.InitElements(Driver, this);
}
}
}
Suggestions please to help me resolve this.
Thanks
The line public HomePage homepage = new HomePage(Driver); in BasePage will be executed before the constructor. It will create new HomePage object with the driver (null at this point) which in turn initialize the Driver property with null.
I suggest you create some kind of support class which will hold the HomePage instance instead of BasePage.
If you insist on keeping it there (not a good design IMHO) creat a constructor which will receive a HomePage object as parameter.

Fody MethodDecorator not working

I am trying to create a method decorator using Fody but it gives me the following error:
I have taken specific care to not wrap my IMethodDecorator inside any namespace as has been mentioned in a lot of places online. Following is the sample code I am trying in a console app.
IMethodDecorator
using System;
using System.Reflection;
public interface IMethodDecorator
{
void OnEntry(MethodBase method);
void OnExit(MethodBase method);
void OnException(MethodBase method, Exception exception);
}
MethodDecoratorAttribute
using System;
using System.Diagnostics;
using System.Reflection;
using FODYPOC;
// Atribute should be "registered" by adding as module or assembly custom attribute
[module: MethodDecorator]
namespace FODYPOC
{
// Any attribute which provides OnEntry/OnExit/OnException with proper args
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Assembly | AttributeTargets.Module)]
public class MethodDecoratorAttribute : Attribute, IMethodDecorator
{
// instance, method and args can be captured here and stored in attribute instance fields
// for future usage in OnEntry/OnExit/OnException
public MethodDecoratorAttribute() { }
public void OnEntry(MethodBase method)
{
Console.WriteLine();
}
public void OnExit(MethodBase method)
{
Console.WriteLine();
}
public void OnException(MethodBase method, Exception exception)
{
Console.WriteLine();
}
}
public class Sample
{
[MethodDecorator]
public void Method()
{
Debug.WriteLine("Your Code");
}
}
}
Can someone point me in the right direction. It looks pretty simple to implement and I know I am making a very silly mistake somewhere.
Apparently the latest version of MethodDecorator.Fody (Version 0.9.0.6 currently) was not working. Downgrading the version to version 0.8.1.1 fixed the issue for me.
After a little more investigation, it appears that the interface method signatures were different in the two versions. So when I had the new package, it was not expecting MethodBase as a parameter and due to not finding anything that matches the interface it expects, it was throwing the error.

How configure LightInject in ASP.NET MVC?

I use SimpleInjector in mvc with this code
public static class SimpleInjectorInitializer
{
public static void Initialize()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container container)
{
container.Register<IPersonRepository, PersonEntityRepository>();
}
}
but now I want to test LightInject Ioc in my mvc application but How ?
I wrote this code
[assembly: WebActivator.PostApplicationStartMethod(typeof(LightInjectInitializer), "InitializeLI")]
public static class LightInjectInitializer
{
public static void InitializeLI()
{
var container = new ServiceContainer();
InitializeContainer(container);
container.RegisterControllers(Assembly.GetExecutingAssembly());
container.EnableMvc();
}
private static void InitializeContainer(ServiceContainer container)
{
container.Register(typeof(PersonEntityRepository), typeof(IPersonRepository), new PerScopeLifetime());
}
}
but show me this error
No parameterless constructor defined for this object.
Can anyone help me for writing equivalent code that working in MVC ?
Sample Code : Download
I am the author of LightInject and would like to help you out.
This static initialize method? Where is it called from.
The reason that you get this error is probably because the initialize code did not execute.
If you would like further assistance, it would be valuable to see what you have in global.asax.cs.
This page also contains information about how to set this up.
http://www.lightinject.net/#mvc
Please change the controller registration line to:
container.RegisterControllers(typeof(MVCApplicationNamespace.Controllers.HomeController).Assembly);