Passing values to Specflow Scenario methods from feature file - c#

I have a custom tag defined in my Hook.cs file like
[BeforeScenario("AfterUpgradeTag")]
public void BeforeScenarioAfterUpgrade()
{
// Code execution here
}
What I want to do is I want to change its method definition like
[BeforeScenario("AfterUpgradeTag")]
public void BeforeScenarioAfterUpgrade(bool flag)
{
if(flag)
// Code execution here
else
//Do a clean up
}
And I want to use this in feature file as something like
#AfterUpgradeTag(bool val = false)
I have searched alot for this. I want to know is this possible using Specflow or if there are any alternatives

I am not sure if you can pass parameters like that in feature file but you can utilize tags to achieve your goal
In feature file do this
#upgrade #false
Scenario: testing upgrade
In binding class
public static ScenarioContext _scenarioContext;
and binding class constructor
public BindingClass(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}
and your BeforeScenario method is defined like this in the class BindingClass
[BeforeScenario("upgrade")]
public void BeforeScenarioUpgradeFalseorTrue()
{
if (BindingClass._scenarioContext.ScenarioInfo.Tags.Contains("false"))
{
log.Info("upgrade is false..");
}
if (BindingClass._scenarioContext.ScenarioInfo.Tags.Contains("true"))
{
log.Info("upgrade is true..");
}
}
when you want to pass true in feature file just do
#upgrade #true
Scenario: testing upgrade

You can follow the documentation from specflow to achieve this.

Related

Dynamic Summary for Swagger documentation

Trying to make a flexible way for documentation in .net core swagger when using shared code between services.
Please have a look at this example:
public abstract class Err
{
/// <summary>
/// The error x
/// </summary>
public abstract string Code { get; }
}
public class Err1 : Err
{
public override string Code { get => "100"; }
}
public class Err2 : Err
{
public override string Code { get => "200"; }
}
public class Err3 : Err
{
public override string Code { get => "300"; }
}
[Route("api/test")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Err), StatusCodes.Status400BadRequest)]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
public ActionResult Get()
{
int i = (new Random().Next(1, 11));
if (1 < 4)
return BadRequest(new Err1());
if (i < 7)
return BadRequest(new Err2());
return Ok("OK");
}
}
This will of course produce a swagger looking something like this:
What I would like to have instead is something like this:
So the important thing here is that the code=300 is NOT included in the summary, because it is not being used in this assembly.
So what I've been thinking of here is;
Is it possible to do some reflection, find all inherited classes being used and write that to the XML (while compiling?) instead of the ordinary summary part?
Override how Swagger read the summary and write your own code.
Can you hook up some Swagger middleware to handle this so it does not read from the XML?
If the reflection part is not possible, of course the next best thing would be in some way to hardcode a list of all the Error-classes being used for this particular services.
Any ideas here guys?
So,
for the first part, what I understand it is not possible to find out if a class is used or not via reflection :(
And for the second part, if you replace the swashbuckle with nswag you are actually able to have this nice "one of" -feature in the swagger UI :) But in my case that is not enough so I guess this is not possible right now.

Extending StepDefinitions in Specflow

I trying to experiment with Specflow. So I am writing functional tests for a REST API and have created a couple of step definitions, say CreatePersonStepDefinitions and GetPeopleStepDefinition
Those extend CommonStepDefinition, which provides things like:
[Given(#"a valid API key is given")]
public void AValidApiKeyIsGiven()
{
ApiKey = "Some Api Key";
}
[Then(#"the response HTTP code should be (.*)")]
public void ThenTheStatusCodeShouldBe(int statusCode)
{
Assert.AreEqual (statusCode, (int)Response.StatusCode);
}
This is to be able to run scenarios like
Given I am retrieving all people
And an invalid API key is given
When I make the call
Then the response HTTP code should be 200
And the API response code is 104
And the API call didn't take more than 200 milliseconds
So there are several common steps between step definitions. I understand that I cannot do this as Steps are global. What I wanted to ask is whats the best way (i.e. best practise) to achieve this without duplicating the same steps in every step definition.
Thanks
Because steps are global you don't need to duplicate them in every step definition, you can just use them in ALL features, and specflow will call them.
If your real question is how do I share the ApiKey and Response between my features steps and my common steps there are a few ways but what I would recommend is to use the context injection approqach from the link. I would create context objects and pass these to your step classes. Specflow has a simple DI framework which will do this automatically (most of the time) for you.
I would create something like this:
public class SecurityContext
{
public string ApiKey {get;set;}
}
public class ResponseContext
{
public IHttpResponse Response{get;set;}
}
[Binding]
public class CommonSteps
{
private SecurityContext securityContext;
private ResponseContext responseContext;
public CommonSteps(SecurityContext securityContext,ResponseContext responseContext)
{
this.securityContext = securityContext;
this.responseContext = responseContext;
}
[Given(#"a valid API key is given")]
public void AValidApiKeyIsGiven()
{
securityContext.ApiKey = "Some Api Key";
}
[Then(#"the response HTTP code should be (.*)")]
public void ThenTheStatusCodeShouldBe(int statusCode)
{
Assert.AreEqual (statusCode, (int)responseContext.Response.StatusCode);
}
}
public class MyFeatureSteps
{
private SecurityContext securityContext;
private ResponseContext responseContext;
public MyFeatureSteps(SecurityContext securityContext,ResponseContext responseContext)
{
this.securityContext = securityContext;
this.responseContext = responseContext;
}
///Then in your feature steps you can use the Api key you set and set the response
}
you might even consider not having Common steps as this get just be a big bucket for everything that is not feature specific, but what we usually do is to break the step classes into something like SecuritySteps which would just take the SecurityContext and ResponseSteps which would just take the ResponseContext

Can I access custom method attributes with an aspect-oriented approach?

For example: I have a custom attribute class similar to the following:
[System.AttributeUsage(System.AttributeTargets.Method)
]
public class Yeah: System.Attribute
{
public double whatever = 0.0;
}
Now I decorate some method with it like that:
[Yeah(whatever = 2.0)]
void SampleMethod
{
// implementation
}
Is it possible to access the Yeah-attribute through injecting the code via aspects? I would prefer the postsharp framework for AOP but I am also happy with any other solution because I think that there is such a feature in postsharp but only available in the professional edition (mentioned here: PostSharp Blog)
Take a look on NConcern .NET AOP Framework. This is a new open source project on which I actively work.
//define aspect to log method call
public class Logging : IAspect
{
//define method name console log with additional whatever information if defined.
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//get year attribute
var year = method.GetCustomAttributes(typeof(YearAttribute)).Cast<YearAttribute>().FirstOrDefault();
if (year == null)
{
yield return Advice.Basic.After(() => Console.WriteLine(methode.Name));
}
else //Year attribute is defined, we can add whatever information to log.
{
var whatever = year.whatever;
yield return Advice.Basic.After(() => Console.WriteLine("{0}/whatever={1}", method.Name, whatever));
}
}
}
public class A
{
[Year(whatever = 2.0)]
public void SampleMethod()
{
}
}
//Attach logging to A class.
Aspect.Weave<Logging>(method => method.ReflectedType == typeof(A));
//Call sample method
new A().SampleMethod();
//console : SampleMethod/whatever=2.0
My logging aspect simply write method name when method called. it include whatever information when it is defined.

How to set up individual tracing / logging with SpecFlow

For my SpecFlow tests, I want to setup an individual logging / tracing of the test progress during the execution of tests. E.g. i want to write
all passed / failed steps
started / ended scenarios
started / ended features
to the windows event log (in order to synchronize it with event log messages generated by other system components during the test).
I tried to use the [BeforeFeature], [BeforeScenario], [BeforeStep] Hooks for doing that, but it turned out that I do not have all the required information within this hooks. E.g. i do not know how to get the current text line of the current step executed (including line information, etc.) or the result (failed / passed) of the current step.
Is there a way to get this information within those hooks or in any other way during the execution of the test?
If not:
Is there a way to customize the trace output created by Specflow in any other way?
In order to provide a custom implementation of ITestTracer you should create a plugin for SpecFlow.
Create a class library project with a name CustomTracer.SpecflowPlugin. CustomTracer is your name of choice for plugin.
Then put the following code into your new assembly
[assembly: RuntimePlugin(typeof(CustomTracer.SpecflowPlugin.CustomTracerPlugin))]
namespace CustomTracer.SpecflowPlugin
{
public class CustomTracerPlugin : IRuntimePlugin
{
public void RegisterDependencies(ObjectContainer container)
{
}
public void RegisterCustomizations(ObjectContainer container, RuntimeConfiguration runtimeConfiguration)
{
container.RegisterTypeAs<CustomTracer, ITestTracer>();
}
public void RegisterConfigurationDefaults(RuntimeConfiguration runtimeConfiguration)
{
}
}
public class CustomTracer : ITestTracer
{
// Your implementation here
}
}
Compile assembly and put in the project folder where your specs are (where .csprog file is).
Edit app.config, specFlow section to include:
<plugins>
<add name="CustomTracer" path="." type="Runtime"/>
</plugins>
That is it. Your plugin should load and your custom ITracer implementation should be called during scenario execution. You can even debug it, if you run scenarios under debug.
Finally, after some investigation, i found out that you can replace the DefaultTraceListener by your own implementation by implementing the Interface ITraceListener:
public class foo: TechTalk.SpecFlow.Tracing.ITraceListener
{
public void WriteTestOutput(string message)
{
EventLog.WriteEntry("mysource", "output: " + message);
}
public void WriteToolOutput(string message)
{
EventLog.WriteEntry("mysource", "specflow: " + message);
}
}
And modifying your App.config configuration by adding this to the "specflow" section:
<trace traceSuccessfulSteps="true"
traceTimings="false"
minTracedDuration="0:0:0.1"
listener="MyNamespace.foo, MyAssemblyName"/>
However, this is more a "workaround" for me since I don't have typed information (e.g. of the StepInstance class) and I have to rely or modify the output formatting of SpecFlow.
I would prefer replacing the TestTracer (ITestTracer) implementation by my own one in some way, but i did not find a way to do this. Does anyone now how to do it?
In Specflow 2.1 its a little different.
Instead of:
public class CustomTracerPlugin : IRuntimePlugin
{
public void RegisterDependencies(ObjectContainer container)
{
}
public void RegisterCustomizations(ObjectContainer container, RuntimeConfiguration runtimeConfiguration)
{
container.RegisterTypeAs<CustomTracer, ITestTracer>();
}
public void RegisterConfigurationDefaults(RuntimeConfiguration runtimeConfiguration)
{
}
}
Do this:
public class CustomTracerPlugin : IRuntimePlugin
{
public void Initialize(RuntimePluginEvents runtimePluginEvents, RuntimePluginParameters runtimePluginParameters)
{
runtimePluginEvents.CustomizeTestThreadDependencies += (sender, args) => { args.ObjectContainer.RegisterTypeAs<CustomTracer, ITestTracer>(); };
}
}
Every thing else is the same as Vladimir Perevalovs answer.
To register a custom ITestTracer in SpecFlow 3.x:
[assembly: RuntimePlugin(typeof(CustomTracerPlugin))]
public class CustomTracerPlugin : IRuntimePlugin
{
public void Initialize(
RuntimePluginEvents runtimePluginEvents,
RuntimePluginParameters runtimePluginParameters,
UnitTestProviderConfiguration unitTestProviderConfiguration)
{
runtimePluginEvents.CustomizeGlobalDependencies +=
(s, ea) => ea.ObjectContainer.RegisterTypeAs<CustomTracer, ITestTracer>();
}
}
public class CustomTracer : ITestTracer
{
...
}

How to mock ConfigurationManager.AppSettings with moq

I am stuck at this point of code that I do not know how to mock:
ConfigurationManager.AppSettings["User"];
I have to mock the ConfigurationManager, but I don't have a clue, I am using Moq.
Someone can give me a tip? Thanks!
I am using AspnetMvc4. A moment ago I wrote
ConfigurationManager.AppSettings["mykey"] = "myvalue";
in my test method and it worked perfectly.
Explanation: the test method runs in a context with app settings taken from, typically a web.config or myapp.config. ConfigurationsManager can reach this application-global object and manipulate it.
Though: If you have a test runner running tests in parallel this is not a good idea.
I believe one standard approach to this is to use a facade pattern to wrap the configuration manager and then you have something loosely coupled that you have control over.
So you would wrap the ConfigurationManager. Something like:
public class Configuration: IConfiguration
{
public string User
{
get
{
return ConfigurationManager.AppSettings["User"];
}
}
}
(You can just extract an interface from your configuration class and then use that interface everywhere in your code)
Then you just mock the IConfiguration. You might be able to implement the facade itself in a few different ways. Above I chose just to wrap the individual properties. You also obtain the side benefit of having strongly typed information to work with rather than weakly typed hash arrays.
Maybe is not what you need to accomplish, but have you considered to use an app.config in your test project?
So the ConfigurationManager will get the values that you put in the app.config and you don't need to mock anything.
This solution works nice for my needs, because I never need to test a "variable" config file.
You can use shims to modify AppSettings to a custom NameValueCollection object. Here is an example of how you can achieve this:
[TestMethod]
public void TestSomething()
{
using(ShimsContext.Create()) {
const string key = "key";
const string value = "value";
ShimConfigurationManager.AppSettingsGet = () =>
{
NameValueCollection nameValueCollection = new NameValueCollection();
nameValueCollection.Add(key, value);
return nameValueCollection;
};
///
// Test code here.
///
// Validation code goes here.
}
}
You can read more about shims and fakes at, Isolating Code Under Test with Microsoft Fakes. Hope this helps.
Have you considered stubbing instead of mocking? The AppSettings property is a NameValueCollection:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Arrange
var settings = new NameValueCollection {{"User", "Otuyh"}};
var classUnderTest = new ClassUnderTest(settings);
// Act
classUnderTest.MethodUnderTest();
// Assert something...
}
}
public class ClassUnderTest
{
private readonly NameValueCollection _settings;
public ClassUnderTest(NameValueCollection settings)
{
_settings = settings;
}
public void MethodUnderTest()
{
// get the User from Settings
string user = _settings["User"];
// log
Trace.TraceInformation("User = \"{0}\"", user);
// do something else...
}
}
The benefits are a simpler implementation and no dependency on System.Configuration until you really need it.
I fear I need to recall what I said. ConfigurationManager.AppSettings sporadically behaves strange, like if it would not always immediately yield the values just written. We had sporadic unit test failures on our build machines due to this. I had to rewrite my code to use a wrapper, returning ConfigurationManager.AppSettings in the usual case and test values in unit tests.
How about just setting what you need? Because, I don't want to mock .NET, do I...?
System.Configuration.ConfigurationManager.AppSettings["myKey"] = "myVal";
You probably should clean out the AppSettings beforehand to make sure the app only sees what you want it to.
That is a static property, and Moq is designed to Moq instance methods or classes that can be mocked via inheritance. In other words, Moq is not going to be any help to you here.
For mocking statics, I use a tool called Moles, which is free. There are other framework isolation tools, like Typemock that can do this too, though I believe those are paid tools.
When it comes to statics and testing, another option is to create the static state yourself, though this can often be problematic (as, I'd imagine it would be in your case).
And, finally, if the isolation frameworks are not an option and you're committed to this approach, the facade mentioned by Joshua is a good approach, or any approach in general where you factor client code of this away from the business logic that you're using to test.
Another way to achieve this goal is to just provide your own IConfiguration, pulling from any file you'd like it to pull from, like this:
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();
Now, as long as you have the values you need for testing in this JSON file, it's very easy to override and change values.
I think writing you own app.config provider is a simple task and is more useful then anything else. Especially you should avoid any fakes like shims etc. because as soon as you use them Edit & Continue no longer works.
The providers I use look like this:
By default they get the values from the App.config but for unit tests I can override all values and use them in each test independently.
There's no need for any interfaces or implement it each time over and over again. I have a utilities dll and use this small helper in many projects and unit tests.
public class AppConfigProvider
{
public AppConfigProvider()
{
ConnectionStrings = new ConnectionStringsProvider();
AppSettings = new AppSettingsProvider();
}
public ConnectionStringsProvider ConnectionStrings { get; private set; }
public AppSettingsProvider AppSettings { get; private set; }
}
public class ConnectionStringsProvider
{
private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public string this[string key]
{
get
{
string customValue;
if (_customValues.TryGetValue(key, out customValue))
{
return customValue;
}
var connectionStringSettings = ConfigurationManager.ConnectionStrings[key];
return connectionStringSettings == null ? null : connectionStringSettings.ConnectionString;
}
}
public Dictionary<string, string> CustomValues { get { return _customValues; } }
}
public class AppSettingsProvider
{
private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public string this[string key]
{
get
{
string customValue;
return _customValues.TryGetValue(key, out customValue) ? customValue : ConfigurationManager.AppSettings[key];
}
}
public Dictionary<string, string> CustomValues { get { return _customValues; } }
}

Categories

Resources