Is it possible to add tags or have multiple BeforeTestRun hooks in Specflow - selenium

So I currently have an automation pack that I have created using Selenium/Specflow.
I wanted to know whether it is possible to have multiple BeforeTestRun hooks?
I've already tried: [BeforeTestRun("example1")] but I receive an error stating BeforeTestRunAttribute does not contain a constructor that takes 1 arguments
I tried the following but that also failed:
[BeforeTestRun]
[Scope(Tag = "example1")]
And referenced the above in the .feature file like this:
#example1
Scenario: This is an example
Given...
When...
Then...
Is there a way to implement this correctly such that in one .feature file I can have two scenarios that can use different [BeforeTestRun]?

If you cannot use [BeforeScenario] like suggested, you can try to manually check for tags using if statements. To get the current tags and compare them to the ones you need, try this:
var tags = ScenarioContext.ScenarioInfo.Tags;
if (tags.Any(x => x.Equals("MyTag")))
{
DoWork();
}
More info here: https://stackoverflow.com/a/42417623/9742876

Related

Karate Runner with ExecutionHook listener

#Peter - As per your suggestion from my previous queries, I have used ExecutionHooks to implement ReportPortal. I am finding difficulties in passing all the required values from my Runner to Base Runner. Below is my configuration-
BaseRunner.java
Results results = Runner.parallel(tags,path,ScenarioName,Collections.singletonList(new
ScenarioReporter()),threads,karateOutputPath);
Runner.java
#KarateOptions(tags = { "#Shakedown" },
features = "classpath:tests/Shakedown"
)
I want to understand how can I pass the attributes like Scenario Name, path and tags. ScenarioReporter() is my class where I have implemented Execution Hook. I have a base runner that will have all the details and a normal runner that will have minimal information. I have just given snippets, please don't mind if there are some syntactical errors.
You don't need the annotations any more, and you can set all parameters including tags using the new "builder" (fluent interface) on the Runner. Refer the docs: https://github.com/intuit/karate#parallel-execution
Results results = Runner.path("classpath:some/package").tags("~#ignore").parallel(5);
So it should be easier to inherit from base classes etc. just figure out a way to pass a List<String> of tags and use it.
Just watch out for this bug, fixed in 0.9.6.RC1: https://github.com/intuit/karate/issues/1061

Is there any API in JUnit 5 to test for included or excluded Tags?

I'd like to enable a test if a certain tag is "included", i.e. passed with option --include-tag of the ConsoleLauncher or useJUnitPlatform.includeTags property in Gradle. Is there any API to retrieve the value of this option in the context of test class or method?
I tried the script-based condition #EnabledIf like this:
#EnabledIf("'true' == systemProperty.get('itest.backendSystemPresent') || junitTags.contains('BackendSystemIT') == true")
But junitTags contains the #Tag annotations of the element in question, not the tags included at runtime.
Reading your question again, my answer is "No". You can't use junitTags to achieve your goals. And no, there's no such API at the moment. You would need something like:
#EnabledIf("'true' == evaluateTagExpression('BackendSystemIT') || ...)
Because you need to take care of tag expression here as well: https://junit.org/junit5/docs/current/user-guide/#running-tests-tag-expressions
But, tags are evaluated earlier in the process. Your condition will not get a chance to be executed when the test was already excluded by tag evaluation. So, I guess, you'll have to stick with the single system property switch to control the enabled state of the test method.
Btw. we are improving the tag expression language with any() and none() tokens, soon. https://github.com/junit-team/junit5/issues/1679
Possible solution:
Annotate your test with #Tag("BackendSystemIT")
Before running your tests, check for itest.backendSystemPresent system property and if it is set, pass a --include-tag "BackendSystemIT" to the test run.
Let Jupiter do the job of evaluating tag expressions
Is there any API to retrieve the value (of this option) of all tags that are attached directly or inherited in the context of test class or method?
Yes. Declare and use a org.junit.jupiter.api.TestInfo parameter in your test method.
#Test
#DisplayName("TEST 1")
#Tag("my-tag")
void test1(TestInfo testInfo) {
assertEquals("TEST 1", testInfo.getDisplayName());
assertTrue(testInfo.getTags().contains("my-tag"));
}
For details see https://junit.org/junit5/docs/current/user-guide/#writing-tests-dependency-injection
But junitTags contains the #Tag annotations of the element in question, not the tags included at runtime.
This is the expected behaviour -- the platform (here: console launcher) already applied the filter passed via --include-tag and other configuration parameters. In short: there's no need to manually check for tags in standard Jupiter tests. If there's problem with the built-in filtering, please create an issue here: https://github.com/junit-team/junit5/issues/new/choose

Cucumber - how to get scenario tag that is currently being executed

I have scenario with multiple tags. For example, #registration, #smoke, #core.
I have a configuration file (test.conf.js file) in which I set targeted tests to be run like this:
cucumberOpts: {
tags: ['#registration', '~#WIP']
}
Running this configuration will only run scenarios with #registration tag.
With this I can get and iterate through all scenario tags (in this case #registration, #smoke, #core):
beforeScenario: function (scenario) {
tags = scenario.getTags();
tags.forEach(function (scenarioTagItem) { ... });
}
My question is how to get in the above function the tag that the test is currently running against? So how to recognize that currently running tag is #registration? Sort of to recognize it as an active tag?
Please help :)
Just called this.cucumberOpts.tags because it was in the same file and build my logic further on that. Stupid overlook from my side :/
Even better way to do it is browser.options.cucumberOpts.tags

How to use Global Property name in my JSON input request using SoapUI?

I have a SoapUI project which contains around 60 plus services. Each service requires some input which will be changed for every execution. So I have created certain Global Properties and assign some values to that properties.
I have to use these properties values in my SoapUI request ( i.e. JSON Format request ).
If it is groovy script means, I will use like this.
String HTiC_Username = com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils.globalProperties['HTiC_Username'].value;
But, how to get the value of the Global Property in the request?
Hope you understand my question. Please provide proper guidance.
Thanks
To dynamically "expand" (i.e. substitute) the value of a property into a test step, the following syntax is used: ${#scope#propertyName}
...where 'scope' refers to the level at which the property has been defined (e.g. Global, Project, TestSuite, TestCase).
So to expand a property named username defined as a Global property, for example, the following code can be used directly within a Request Test Step (e.g within a JSON body, or header value, etc):
${#Global#username}
To access the same property value within a Groovy Test Step, you can use the following syntax:
context.expand('${#scope#propertyName}')
...as in the following example:
context.expand('${#Global#username}')
What we did was the following:
created a test data file to store all the specific input data for the different services (testdata.properties)
Example content of testdata.properties:
Billing_customerID=1234567
OtherService_paymentid=12121212
....
create a SoupUi global parameter (File/Preferences/Global properties): testdata_filepath=C:\...
For specific services we added a Properties test step. You can specify the "Load from" field to our new global parameter: ${#Global#testdata_filepath} Now you can use the Load button to load parameters.
Finally you can reference the parameter in your xml in the following format: ${Properties#Billing_customerID}
Example content of a service with parameter:
...
<BillingCustomerIdentification>
<BillingCustomerID>${#Properties#Billing_customerID}</BillingCustomerID>
</BillingCustomerIdentification>
...
To set up your projects in this manner also helps to automate service tests eg. using Hudson (see my previous SO answer).
If it is too heavy and automation is not a target, you can simply use ${#Global#someinputvariable} format in your xml ;-)

How to update the values of Magento products using installer/update scripts and Magento abstractions?

I added a custom eav attribute to my Magento application product entity using an installer script (Basically, following the procedure described here: Installing Custom Attributes with Your Module). Now, I want to use an update script to change (populate) the values of this attribute for each product according to some criteria (based on the product category). The script I attempted to use was essentially like this:
$attributeValues = array(...) // Map from $productId to the desired $value
$product = Mage::getModel('catalog/product');
foreach($attributeValues as $productId=>$value){
$product->load($productId)->setMyAttribute($value);
$product->save();
}
My questions would then be: Is it ok to use this level of abstraction (Mage::getModel('catalog/product') and its methods) in update scripts? If it isn't, how would you recommend to change these attribute values using update scripts (without requiring sql)?
The script I used (until now) has not worked and failed with the error:
Call to a member function getStoreIds() on a non-object
in a magento core file.
I don't know if this error is a Magento bug or is a problem with how I'm using the update scripts.
I'm using Magento 1.4.0.1
Data update scripts are the way to go
Simply use a data upgrade script for this. This is a script placed in the data folder instead of the sql folder. Those scripts run later then the database structure updates, and allow access to more functionality.
Example file names:
app/code/local/My/Module/data/your_setup/data-install-0.1.0.php
app/code/local/My/Module/data/your_setup/data-upgrade-0.1.0-0.2.0.php
This is already available in Magento 1.4.
Try adding Mage::app()->setUpdateMode(false) in your sql upgrade script. e.g.
$installer = new Mage_Eav_Model_Entity_Setup('core_setup');;
$installer->startSetup();
Mage::app()->setUpdateMode(false);
Mage::app()->setCurrentStore('your_store_code_here');
If you look in Mage::app()->getStore() you will see the following snippet that returns an incorrect store which is required for saving a product.
if (!Mage::isInstalled() || $this->getUpdateMode()) {
return $this->_getDefaultStore();
}