In a project where we're using cucumber-jvm for our webtests, I've come across a problem which so far I haven't been able to solve: Se have several Scenario Outlines which should all use the same Examples. Now, of course I can copy these examples to every single one, but it would be much shorter (and probably easier to understand) if you could do something like this:
Background:
Examples:
| name |
| Alice |
| Bob |
Scenario Outline: Flying to the conference
Given I'm flying to a confernce
When I try to check in at the airport
And my name is <name>
Then I should get my plane ticket
Scenario Outline: Collecting the conference ticket
Given I'm at a conference
When I ask for the ticket for <name>
And show my business card to prove my id
Then I should get my conference ticket
Scenario Outline: Collectiong my personalized swag bag
Given I'm at a conference
When I go to the first booth
And show them my conference ticket with the name <name>
Then they'll give me a swag bag with the name <name> printed onto it
Is something like that possible? If so, how? Would I use some kind of factory as is suggested here? If so, any recomendations?
If you combined the three scenarios into one scenario then what you want to achieve is trivial. Breaking them out into separate scenarios allows
Each to run (and fail) independently
Have a separate line in the report
If you are willing to forgo the former and combine the three into one scenario then I can suggest a solution that supports the latter. Cucumber-jvm does support the ability to write text into a report in an (After) hook via the Scenario object. In your step definition class define as a class variable
private List<String> stepStatusList;
You can initialize it in the step definition's class constructor.
this.stepStatusList = new ArrayList<String>();
In the last step of each of the formally three scenarios add text into stepStatusList with the status that you want to appear in the report.
this.stepStatusList.add("Scenario sub-part identifier, some status");
In the After hook, write the lines into the report. This sample assumes that you want to write the lines independently of the success or failure of the scenario.
#Before
public void setup_cucumber_spring_context(){
// Dummy method so cucumber will recognize this class as glue
// and use its context configuration.
}
#After
public void captureScreenshotOnFailure(Scenario scenario) {
// write scenario-part status into the report
for (String substatus : this.stepStatusList) {
scenario.write(substatus);
}
// On scenario failure, add a screenshot to the cucumber report
if (scenario.isFailed() && webDriver != null) {
try {
WebDriver augemented = new Augmenter().augment(webDriver);
byte[] screenshot = ((TakesScreenshot) augemented).getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
I am considering using SpecFlow for a new automation project. Since SpecFlow is similar to Cucumber in the Java world this question applies to Cucumber as well.
In real world applications there are lists of complex objects and tests are required to look just for specific object in those lists and only for specific fields of.
For example, a chat application displays a list of messages, a message being a complex object comprising of a date, user name, user icon image, text, and maybe other complex objects like images, tables, etc.
Now, one test may require just to check that the chat is not empty. Other test may require just to check that a message from a specific user is present. And another one just to check for a message with a specific text. The amount of verification rules can grow into many tens.
Of course, one way to deal with that is to implement a "step" for each verification rule, hence writing tens of steps just to discover that yet another one is needed... :(
I found that a better way is to use NUnit Constrains (Hamcrest Matchers in Java) to define those rules, for example:
[Test]
public void ShouldNotBeEmpty() {
...
Assert.That(chatMessages, Is.Not.Empty);
}
[Test]
public void ShouldHaveMessageFrom(string user) {
...
Assert.That(chatMessages, Contains.Item(new Message() with User=user));
// sometimes the User field maybe a complex object too...
}
[Test]
public void ShouldHaveMessage(string text) {
...
Assert.That(chatMessages, Contains.Item(new Message() with Text=text));
}
This way the mechanism that brings chatMessages can work with any kind of verification rule. Hence in a BDD framework, one could make a single step to work for all:
public void Then_the_chat(IConstraint matcher) {
Assert.That(someHowLoadChatMessagesHere, matcher);
}
Is there any way in SpecFlow/Cucumber to have these rules mapped to Gerkin syntax?
Code reuse is not the biggest concern for a behavior-driven test. Accurately describing the business use case is what a BDD test should do, so repetitive code is more acceptable. The reality is that you do end up with a large number of step definitions. This is normal and expected for BDD testing.
Within the realm of a chat application, I see three options for writing steps that correspond to the unit test assertions in your question:
Unit Test:
[Test]
public void ShouldNotBeEmpty() {
...
Assert.That(chatMessages, Is.Not.Empty);
}
Gherkin:
Then the chat messages should not be empty
Unit Test:
[Test]
public void ShouldHaveMessageFrom(string user) {
...
Assert.That(chatMessages, Contains.Item(new Message() with User=user));
// sometimes the User field maybe a complex object too...
}
Gherkin:
Then the user should have a chat message from "Greg"
Unit Test:
[Test]
public void ShouldHaveMessage(string text) {
...
Assert.That(chatMessages, Contains.Item(new Message() with Text=text));
}
Gherkin:
Then the user should have a chat message with the following text:
"""
Hi, everyone!
How is the weather, today?
"""
Unit Test:
public void Then_the_chat(IConstraint matcher) {
Assert.That(someHowLoadChatMessagesHere, matcher);
}
This gets a little more difficult. Consider using a data table to specify a more complex object in your assertion in Gherkin:
Then the user should have the following chat messages:
| Sender | Date Sent | Message |
| Greg | 5/2/2022 9:24:18 AM | ... |
| Sarah | 5/2/2022 9:25:39 AM | ... |
SpecFlow will pass a Table object as the last parameter to this step definition. You can use the SpecFlow.Assist Table helpers to compare the data table to your expected messages.
This gives you some options to think about. Which one you choose should be determined by how well the step and scenario reads in Gherkin. Without more information, this is all I can provide. Feel free to try these out and post new questions concerning more specific problems.
I would like somehow get list of all tags which I used in my project and get all names of cucumber scenarios which I have in my project without run tests. Could someone helps me how can I do this?
As suggested by #mpkorstanje you can create a custom plugin for this.
public class DryRunPlugin implements EventListener {
#Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, this::handleCaseStarted);
}
private void handleCaseStarted(TestCaseStarted event) {
System.out.println(event.getTestCase().getUri());
System.out.println(event.getTestCase().getName());
System.out.println(event.getTestCase().getScenarioDesignation());
event.getTestCase().getTags().stream().forEach(t ->
System.out.println(t.getName()));
}
}
#CucumberOptions(glue = "stepdef", plugin = {
"formatter.DryRunPlugin" }, features = "src/test/resources/feature/", dryRun = true)
You will get the output as below.
file:src/test/resources/feature/scenarios1.feature
Scenario 1
src/test/resources/feature/scenarios1.feature:5 # Scenario 1
#Feature
#ScenarioOne
The sample feature file.
#Feature
Feature: Scenario and Scenario Outline Combination
#ScenarioOne
Scenario: Scenario 1
And this is "FIRST" step
And this is "SECOND" step
As per my best knowledge, cucumber shall not allow you to get list of all tags and scenarios name without executing tests.
May be you would need to use some scripting language like VB Script, search for position of # in file and get tag name and save one by one under a file. Similarly, after Scenario, Outline, get the whole line text and save one by one in a file and repeat same for all files under a directory.
Launch a bash shell and go to the folder. Type:
grep -nri "Scenario:\|Scenario Outline:" .
to get all tests. And:
grep -nri "#" .
To get all tag names
(In both cases, pay attention to the dot at the end of the command line)
I'm using parceler, and I'm trying to define a structure like this one:
Category 1..* Product 1..* Images
Each entity has a list, and a parent instance, like this
#Parcel
public class Category {
List<Product> products;
...
}
#Parcel
public class Product {
List<Image> images;
Category parent;
...
}
#Parcel
public class Image {
Product parent;
...
}
I want to know how performance is affected when I do:
Category c = getSampleCategory(); // With products and images
Parcels.wrap(c);
and pass a Category object as an extra between activities.
I'm noticing ANRs and I ask myself if this is one of the causes
Thanks in advance
Parceler uses annotation processing and, in turn, generated code to marshal your data to and from the Bundle / Intent / Parcel. This means that the Parcels.wrap / Parcels.unwrap calls should be very performant. I'd encourage you to run your own performance benchmark (surround you calls with timer logging) around the various parts of your code, including the wrap / unwrap calls to ensure that things are taking a reasonable amount of time. If you do find that Parceler is not meeting expectations (is a source of your ANRs) please file an issue on the Parceler issue list on Github.
I have been asked the question by one of my customers that they would like to automatically "Capture CC Payment" for Sales orders at the time that the shipper is confirmed.
I know that in Acumatica, there is the batch processing methods to handle doing this in bulk but they'd still like to have it automatically do it as mentioned above.
My initial thoughts were a Customization that will use an Automation Step when the shipper is confirmed to load the order and execute the "Capture CC Payment" step.
More or less a customization step that is composed of
1) A custom method in the shipper screen that loads the order(s) in question and then executes the "Capture CC Payment" button/function
2) An automation step assigned to the shipper at the time of confirmation that executes the above method.
Is this the best way of handling this request or is there another pre-existing method that I might have overlooked?
The customer is currently on 4.20.2115 with no real interest in going to 5.1 anytime soon.
Thank you
If you have a hummer in your hands, everything is a nail :). I can propose you solution from C# prospective. As a solution, I propose you to override method confirm in extension class with usage of delegate. I don't know about which form you are talking about, but lets assume, that form has graph SubmitterManager. Lets also assume, that you want to track method CreatePayment, which has paramethers string, IDictionary, IDictionary. Then you can create graph extension SubmitterManagerExt, and use PXOverride attribute with delegate in the following way:
public class SubmitterManagerExt : PXGraphExtension<SubmitterManager>
{
[PXOverride]
public bool CreatePayment(string viewName,
IDictionary keys,
IDictionary values,
Func<string, IDictionary,
IDictionary, bool> method)
{
// Call your method CreatePayment
bool result = method(viewName, keys, values);
if(result)
{
// here you can add some C# code, which will do something
// with created payments
}
}
return result;
}
}
Given I have two Bounded Contexts:
Fleet Mgt - simple CRUD-based supporting sub-domain
Sales - which is my CQRS-based Core Domain
When a CRUD operation occurs in the fleet management, an event reflecting the operation should be published:
AircraftCreated
AircraftUpdated
AircraftDeleted
etc.
These events are required a) to update various index tables that are needed in the Sales domain and b) to provide a unified audit log.
Question: Is there an easy way to store and publish these events (to the InProcessEventBus, I'm not using NSB here) without going through an AggregateRoot, which I wouldn't need in a simple CRUD context.
If you want to publish the event about something, this something probably is an aggregate root, because it is an externally identified object about a bundle of interest, otherwise why would you want to keep track of them?
Keeping that in mind, you don't need index tables (I understand these are for querying) in the sales BC. You need the GUIDs of the Aircraft and only lookups/joins on the read side.
For auditing I would just add a generic audit event via reflection in the repositories/unit of work.
According to Pieter, the main contributor of Ncqrs, there is no way to do this out of the box.
In this scenario I don't want to go through the whole ceremony of creating and executing a command, then loading an aggregate root from the event store just to have it emit the event.
The behavior is simple CRUD, implemented using the simplest possible solution, which in this specific case is forms-over-data using Entity Framework. The only thing I need is an event being published once a transaction occurred.
My solution looks like this:
// Abstract base class that provides a Unit Of Work
public abstract class EventPublisherMappedByConvention
: AggregateRootMappedByConvention
{
public void Raise(ISourcedEvent e)
{
var context = NcqrsEnvironment.Get<IUnitOfWorkFactory>()
.CreateUnitOfWork(e.EventIdentifier);
ApplyEvent(e);
context.Accept();
}
}
// Concrete implementation for my specific domain
// Note: The events only reflect the CRUD that's happened.
// The methods themselves can stay empty, state has been persisted through
// other means anyway.
public class FleetManagementEventSource : EventPublisherMappedByConvention
{
protected void OnAircraftTypeCreated(AircraftTypeCreated e) { }
protected void OnAircraftTypeUpdated(AircraftTypeUpdated e) { }
// ...
}
// This can be called from anywhere in my application, once the
// EF-based transaction has succeeded:
new FleetManagementEventSource().Raise(new AircraftTypeUpdated { ... });