Check scenario completion status in specflow in after scenario run in parallel - specflow

I have seen facets of this question asked elsewhere but there was no solid answer, so I ideally want to have a couple of [AfterScenario] bindings run and do some logic based upon the completion state, i.e did it pass/fail, and how did it fail etc.
I know there is a ScenarioContext.Current.TestError and some other related classes, but I cannot find docs that indicate if this can be used when tests are run in parallel, so is the above ScenarioContext ok to be used in this context or is there some other way to do it?

You can't use ScenarioContext.Current in parallel execution, but you can get the current ScenarioContext via Context Injection (see https://specflow.org/documentation/Context-Injection/)
So this works in parallel execution:
[Binding]
public class ScenarioStatusBinding
{
private readonly ScenarioContext _scenarioContext;
public ScenarioStatusBinding(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}
[AfterScenario]
public void CheckStatusOfScenario()
{
Console.WriteLine(_scenarioContext.TestError);
Console.WriteLine(_scenarioContext.ScenarioExecutionStatus);
}
}

Related

Can an Azure Function be Executed for Multiple Environments

I've encountered a dependency injection scenario which I cannot find a way through.
We currently have an Azure function.
We are using dependency injection via the FunctionsStartup attribute.
That all works fine, until I get asked to make it work for multiple environments.
The tester found it too onerous to deploy to 7 different environments, so I was asked to re-jig the function so that it runs (in a loop) for those environments.
That means 7 different IConfigurations and somehow having 7 separate compartmentalised IOC registrations of services.
I can't think of a way of doing that, without significantly re-structuring the way abstractions are being resolved. Even if you set up registrations in a loop and inject an IEnumerable of a service, when it goes to resolve a child dependency, it just pulls the last one registered, rather than the one which was meant to correlate with the current item being iterated.
So, something like this (using Autofac):
Registration
foreach (var configuration in configurations)
{
containerBuilder.Register<ICosmosDbService<AccountUsage>>(sp =>
{
var dBConfig = CosmosDBHelper.GetProjectDatabaseConfig(configuration.Value, Project.Jupiter);
return CosmosClientInitializer<AccountUsage>.Initialize(dBConfig);
}).As<ICosmosDbService<AccountUsage>>();
}
Usage
private readonly IEnumerable<IAccountUsageService> _accountUsageService;
public JobScheduler(IEnumerable<IAccountUsageService> accountUsageService)
{
_accountUsageService = accountUsageService;
}
[FunctionName("JobScheduler")]
public async Task Run([TimerTrigger("0 */2 * * * *")] TimerInfo myTimer, ILogger log)
{
log.LogInformation($"Job Scheduler Timer trigger function executed at: {DateTime.Now}");
try
{
foreach (var usageService in _accountUsageService)
{
var logs = await usageService.GetCurrentAccountUsage("gfkjdsasjfa");
// ...
}
}
I realise this kind of DI usage is not ideal (and does not even work).
Is there a way to structure an Azure Function such that it can execute for different configurations in a compartmentalised manner? Or is this really just fighting against the technology?
You've got a couple of ways to do this - either inject the right dependencies into the function constructor, or resolve them dynamically using a service-locater type approach with a named instance.
Let's consider the second approach and what it would mean for your implementation. As you demonstrated, you'd be looping through your instances and resolving the dependency you want to use, then invoking it
foreach (var usageService in _accountUsageService)
{
var logs = await usageService.GetCurrentAccountUsage("named-instance");
logs.DoSomething();
}
This is technically possible, but now you're doing batch processing - you're doing more than once piece of work that's been triggered by a single event (the timer object), which means you have to deal with a couple of extra problems. What should you do if there's a failure with one of the instances, and what to do if one of the instances is running slowly?
Ideally, you want functions to do the smallest bit of work they can, and complete quickly - You don't want failure or slowness with one particular instance impacting the other instances. By breaking it down to the smallest piece of work (think, one event trigger does one piece of work) then you can take advantage of the functions runtime for things like retries on failures, and threading and concurrency is now being done for you by the runtime.
You could then think about a couple of ways you could do this. a) multiple function signatures and a service resolver approach, e.g.
public class JobScheduler
{
public JobScheduler(IEnumerable<IAccountUsageService> accountUsageService)
{
_accountUsageService = accountUsageService;
}
[FunctionName("FirstInstance")]
public Task FirstInstance([TimerTrigger("%MetricPoller:Schedule%")] TimerInfo myTimer)
{
var logs = await _accountUsageService.GetNamedInstance("instance-a");
logs.DoSomething();
}
[FunctionName("SecondInstance")]
public Task SecondInstance([TimerTrigger("%MetricPoller:Schedule%")] TimerInfo myTimer)
{
var logs = _accountUsageService.GetNamedInstance("instance-b");
logs.DoSomething();
}
}
or b), multiple classes with the necessary dependencies injected
public class JobSchedulerFirstInstance
{
public JobSchedulerFirstInstance(ILogs logs)
{
_logs = logs;
}
[FunctionName("FirstInstance")]
public Task FirstInstance([TimerTrigger("%MetricPoller:Schedule%")] TimerInfo myTimer)
{
_logs.DoSomething();
}
}
I'd personally lean towards multiple classes approach, and register named instances with my container. A bit of extra wire up work needed, but you'll end up with lots of small classes that all look very similar that are basically jus t plumbing that the functions runtime executes.

How to Ignore specflow test using programing

I want to execute specflow scenario based on some condition and skip test if condition is not met programmatically.
I have created one test which gets executed for different countries, but I want to execute test only for one country not all.
I tried scenariocontext.current.pending(); In this case steps are getting skipped but in Jenkins, test result is shown as failed.
Since SpecFlow 3.1 you can do it with the UnitTestRuntimeProvider.
[Binding]
public sealed class StepDefinitions
{
private readonly IUnitTestRuntimeProvider _unitTestRuntimeProvider;
public CalculatorStepDefinitions(IUnitTestRuntimeProvider unitTestRuntimeProvider)
{
_unitTestRuntimeProvider = unitTestRuntimeProvider;
}
[When("your binding")]
public void YourBindingMethod()
{
_unitTestRuntimeProvider.TestIgnore("This scenario is always skipped");
}
}
Ignoring is like skipping the scenario. Be careful, as it behaves a little bit different for the different unit test runners (xUnit, NUnit, MSTest, SpecFlow+ Runner).
Also, this works only in step definitions. It is not possible to use it in hooks.

Amazon SWF queries

Over the last couple of years, I have done a fair amount of work on Amazon SWF, but the following points are still unclear to me and I am not able to find any straight forward answers on any forums yet.
These are pretty basic requirements I suppose, sure others might have come across too. Would be great if someone can clarify these.
Is there a simple way to return a workflow execution result (maybe just something as simple as boolean) back to workflow starter?
Is there a way to catch Activity timeout exception, so that we can do run customised actions in such scenarios?
Why doesn't WorkflowExecutionHistory contains Activities, why just Events?
Why there is no simple way of restarting a workflow from the point it failed?
I am considering to use SWF for more business processes at my workplace, but these limitations/doubts are holding me back!
FINAL WORKING SOLUTION
public class ReturnResultActivityImpl implements ReturnResultActivity {
SettableFuture future;
public ReturnResultActivityImpl() {
}
public ReturnResultActivityImpl(SettableFuture future) {
this.future = future;
}
public void returnResult(WorkflowResult workflowResult) {
System.out.print("Marking future as Completed");
future.set(workflowResult);
}
}
public class WorkflowResult {
public WorkflowResult(boolean s, String n) {
this.success = s;
this.note = n;
}
private boolean success;
private String note;
}
public class WorkflowStarter {
#Autowired
ReturnResultActivityClient returnResultActivityClient;
#Autowired
DummyWorkflowClientExternalFactory dummyWorkflowClientExternalFactory;
#Autowired
AmazonSimpleWorkflowClient swfClient;
String domain = "test-domain;
boolean isRegister = true;
int days = 7;
int terminationTimeoutSeconds = 5000;
int threadPollCount = 2;
int taskExecutorThreadCount = 4;
public String testWorkflow() throws Exception {
SettableFuture<WorkflowResult> workflowResultFuture = SettableFuture.create();
String taskListName = "testTaskList-" + RandomStringUtils.randomAlphabetic(8);
ReturnResultActivity activity = new ReturnResultActivityImpl(workflowResultFuture);
SpringActivityWorker activityWorker = buildReturnResultActivityWorker(taskListName, Arrays.asList(activity));
DummyWorkflowClientExternalFactory factory = new DummyWorkflowClientExternalFactoryImpl(swfClient, domain);
factory.getClient().doSomething(taskListName)
WorkflowResult result = workflowResultSettableFuture.get(20, TimeUnit.SECONDS);
return "Call result note - " + result.getNote();
}
public SpringActivityWorker buildReturnResultActivityWorker(String taskListName, List activityImplementations)
throws Exception {
return setupActivityWorker(swfClient, domain, taskListName, isRegister, days, activityImplementations,
terminationTimeoutSeconds, threadPollCount, taskExecutorThreadCount);
}
}
public class Workflow {
#Autowired
private DummyActivityClient dummyActivityClient;
#Autowired
private ReturnResultActivityClient returnResultActivityClient;
#Override
public void doSomething(final String resultActivityTaskListName) {
Promise<Void> activityPromise = dummyActivityClient.dummyActivity();
returnResult(resultActivityTaskListName, activityPromise);
}
#Asynchronous
private void returnResult(final String taskListname, Promise waitFor) {
ActivitySchedulingOptions schedulingOptions = new ActivitySchedulingOptions();
schedulingOptions.setTaskList(taskListname);
WorkflowResult result = new WorkflowResult(true,"All successful");
returnResultActivityClient.returnResult(result, schedulingOptions);
}
}
The standard pattern is to host a special activity in the workflow starter process that is used to deliver the result. Use a process specific task list to make sure that it is routed to a correct instance of the starter. Here are the steps to implement it:
Define an activity to receive the result. For example "returnResultActivity". Make this activity implementation to complete the Future passed to its constructor upon execution.
When the workflow is started it receives "resultActivityTaskList" as an input argument. At the end the workflow calls this activity with a workflow result. The activity is scheduled on the passed task list.
The workflow starter creates an ActivityWorker and an instance of a Future. Then it creates an instance of "returnResultActivity" with that future as a constructor parameter.
Then it registers the activity instance with the activity worker and configures it to poll on a randomly generated task list name. Then it calls "start workflow execution" passing the generated task list name as an input argument.
Then it wait on the Future to complete. The future.get() is going to return the workflow result.
Yes, if you are using the AWS Flow Framework a timeout exception is thrown when activity is timed out. If you are not using the Flow framework than you are making your life 100 times harder. BTW the workflow timeout is thrown into a parent workflow as a timeout exception as well. It is not possible to catch a workflow timeout exception from within the timing out instance itself. In this case it is recommended to not rely on workflow timeout, but just create a timer that would fire and notify workflow logic that some business event has timed out.
Because a single activity execution has multiple events associated to it. It should be pretty easy to write code that converts history to whatever representation of activities you like. Such code would just match the events that relate to each activities. Each event always has a reference to the related events, so it is easy to roll them up into higher level representation.
Unfortunately there is no easy answer to this one. Ideally SWF would support restarting workflow by copying its history up to the failure point. But it is not supported. I personally believe that workflow should be written in a way that it never fails but always deals with failures without failing. Obviously it doesn't work in case of failures due to unexpected conditions. In this case writing workflow in a way that it can be restarted from the beginning is the simplest approach.

Specflow calling steps within steps causes "No matching step definition" error

I am following the technique outlined here
using a step defined like
[Given("some base scenario has happened")]
public void SomeBaseScenarioHasHappened()
{
Given("some condition");
And("some action");
When("some result");
}
from a scenario like
Scenario: Some dependant scenario
Given some condition
And some base scenario has happened
When some other action
Then some other result
However the step
When some other condition
produces the following error
-> No matching step definition found for the step. Use the following code to create one:
[When(#"some other condition")]
public void Whensome other condition()
{
ScenarioContext.Current.Pending();
}
I can work around the problem by having the base scenario only use Given
[Given("some base scenario has happened")]
public void SomeBaseScenarioHasHappened()
{
Given("some condition");
Given"some action");
Given("some result");
}
however this is not what I should have to do.
Am I missing something?
Why cant the base scenario be called using an AND ?
In Specflow there are only 3 types of steps. Given, When and Then. When you use a step with And in your scenario description SpecFlow looks at the previous type of step and assumes that your And step is of the same type.
So when you write this
Scenario: Some dependant scenario
Given some base scenario has happened
And some other condition
When some other action
Then some other result
Specflow looks for step which have bindings:
Given("some base scenario has happened")
Given("some other condition")
When("some other action")
Then("some other result")
Notice there is no And binding?
So your solution is to to ensure that in your composite step you must avoid using And and just use the same binding (or one of them if they have multiple) that the original step had. Your final solution should look something like this:
[Given("some condition")]
public void SomeCondition()
{
...
}
[When("some action")]
public void SomeAction()
{
...
}
[Then("some result")]
public void SomeResult()
{
...
}
[Given("some base scenario has happened")]
public void SomeBaseScenarioHasHappened()
{
Given("some condition");
When("some action");
Then("some result");
}
[Given("some other condition")]
public void SomeOtherCondition()
{
...
}
[When("some other action")]
public void SomeOtherAction()
{
...
}
[Then("some other result")]
public void SomeOtherResult()
{
...
}
You can't use And in the composite steps because no steps are actually bound with an And, there is no such binding - The only bindings are Given, When or Then. The And and But keywords are only used when generating the unit tests that are run, the steps using those keywords are still bound to a Given, When or Then step ultimately.
In a scenario definition the things are processed in order and you can easily tell what an And step actually is based on the step it appears after, so when specflow generates the step bindings it knows what step type to use (either a Given, When or Then). When you are calling a a step from within another step you are explicitly calling one of those step bindings and you have to call it with the binding that it is bound with. So if it was bound with a Given binding like this:
[Given("some other condition")]
public void SomeOtherCondition()
{
...
}
then you have to call it like this from the code:
Given("Some other condition");
but you could refer to it like this in a scenario:
Given some condition
And some other condition
because specflow knows when it generates the unit test that the And some other condition is actually calling a Given bound step
This question has been previously answered correctly above.
I just came across the same error "No matching step definition found for one or more steps".
The reason that I had this issue, was that I had forgotten to put the attribute [Binding, Scope(Feature = "My Feature")] just above my steps c# code class which links methods to feature file, which is needed to match "Feature: My Feature" at the top of my feature file.
I just taught that I would document it here to help someone else that was seeing the same error but for the different reason that I outlined.
Possible solutions
Use Given instead of And
Scenario: Some dependant scenario
Given some base scenario has happened
Given some other condition
When some other action
Then some other result
or
Tag the step with more than one binding, e.g.
[Given(#"some other condition")]
[When(#"some other condition")]
public void Whensome other condition()
{
but this won't always make semantic sense, so use this only when it really does make sense.
try verifying if your sentence has empty spaces. i.e: Given some description(empty space)
so, in the method will appear like: [Given("some description ")]

How do I unit test a custom ant task?

I am writing a custom ant task that extends Task. I am using the log() method in the task. What I want to do is use a unit test while deveoping the task, but I don't know how to set up a context for the task to run in to initialise the task as if it were running in ant.
This is the custom Task:
public class CopyAndSetPropertiesForFiles extends Task {
public void execute() throws BuildException {
log("CopyAndSetPropertiesForFiles begin execute()");
log("CopyAndSetPropertiesForFiles end execute()");
}
}
This is the unit test code:
CopyAndSetPropertiesForFiles task = new CopyAndSetPropertiesForFiles();
task.execute();
When the code is run as a test it gives a NullPointerException when it calls log.
java.lang.NullPointerException
at org.apache.tools.ant.Task.log(Task.java:346)
at org.apache.tools.ant.Task.log(Task.java:334)
at uk.co.tbp.ant.custom.CopyAndSetPropertiesForFiles.execute(CopyAndSetPropertiesForFiles.java:40)
at uk.co.tbp.ant.custom.test.TestCopyAndSetPropertiesForFiles.testCopyAndSetPropertiesForFiles(TestCopyAndSetPropertiesForFiles.java:22)
Does anybody know a way to provide a context or stubs or something similar to the task?
Thanks,
Rob.
Accepted answer from Abarax. I was able to call task.setProject(new Project());
The code now executes OK (except no logging appears in th console - at least I can exercise the code :-) ).
Or better yet, decouple the task object itself from the logic (lets call it TaskImpl) inside the task - so that you can pass in your own dependencies (e.g., the logger). Then, instead of testing the task object, you test TaskImpl -> which you can pass in the logger, and any other weird bits and pieces it might need to do its job. Then unit testing is a matter of mocking the dependencies.
Looking at the Ant source code these are the two relevent classes: ProjectComponent and Task
You are calling the log method from Task:
public void log(String msg) {
log(msg, Project.MSG_INFO);
}
Which calls:
public void log(String msg, int msgLevel) {
if (getProject() != null) {
getProject().log(this, msg, msgLevel);
} else {
super.log(msg, msgLevel);
}
}
Since you do not have project set it will call "super.log(msg, msgLevel)"
public void log(String msg, int msgLevel) {
if (getProject() != null) {
getProject().log(msg, msgLevel);
} else {
// 'reasonable' default, if the component is used without
// a Project ( for example as a standalone Bean ).
// Most ant components can be used this way.
if (msgLevel <= Project.MSG_INFO) {
System.err.println(msg);
}
}
}
It looks like this may be your problem. Your task needs a project context.
Ant has a handy class called BuildFileTest that extends the JUnit TestCase class. You can use it to test the behaviour of individual targets in a build file. Using this would take care of all the annoying context.
There's a Test The Task chapter in the Apache Ant Writing Tasks Tutorial that describes this.

Resources