The business scenario I'm trying to test with cucumber/gherkin (specflow, actually) is that given a set of inputs on a web form, I make a request, and need to ensure that (under certain conditions), when the result is returned, a particular field hasn't changed (under other condition, it does). E.g.
Given I am on the data entry screen
When I select "do not update frobnicator"
And I submit the form
And the result is displayed
Then the frobnicator is not updated
How would I write the step "the frobnicator is not updated"?
One option is to have a step that runs before "I submit the form" that reads something like "I remember the value of the frobnicator", but that's a bit rubbish - it's a horrible leak of an implementation detail. It distracts from the test, and is not how the business would describe this. In fact, I have to explain such a line any time anyone sees it.
Does anyone have any ideas on how this could be implemented a bit nicer, ideally as written?
I disagree with the previous answer.
The gherkin text you felt like you wanted to write is probably right.
I'm going to modify it just a little to make it so that the When step is the specific action that is being tested.
Given I am on the data entry screen
And I have selected "do not update frobnicator"
When I submit the form
Then the frobnicator is not updated
How exactly you Assert the result will depend on how your program updates the frobnicator, and what options that gives you.. but to show it is possible, I'll assume you have decoupled your data access layer from your UI and are able to mock it - and therefore monitor updates.
The mock syntax I am using is from Moq.
...
private DataEntryScreen _testee;
[Given(#"I am on the data entry screen")]
public void SetUpDataEntryScreen()
{
var dataService = new Mock<IDataAccessLayer>();
var frobby = new Mock<IFrobnicator>();
dataService.Setup(x => x.SaveRecord(It.IsAny<IFrobnicator>())).Verifiable();
ScenarioContext.Current.Set(dataService, "mockDataService");
_testee = new DataEntryScreen(dataService.Object, frobby.Object);
}
The important thing to note here, is that the given step sets up the object we are testing with ALL the things it needs... We didn't need a separate clunky step to say "and i have a frobnicator that i'm going to memorise" - that would be bad for the stakeholders and bad for your code flexibility.
[Given(#"I have selected ""do not update frobnicator""")]
public void FrobnicatorUpdateIsSwitchedOff()
{
_testee.Settings.FrobnicatorUpdate = false;
}
[When(#"I submit the form")]
public void Submit()
{
_testee.Submit();
}
[Then(#"the frobnicator is not updated")]
public void CheckFrobnicatorUpdates()
{
var dataService = ScenarioContext.Current.Get<Mock<IDataAccessLayer>>("mockDataService");
dataService.Verify(x => x.SaveRecord(It.IsAny<IFrobnicator>()), Times.Never);
}
Adapt the principle of Arrange, Act, Assert depending on your circumstances.
Think about how you would test it manually:
Given I am on the data entry screen
And the blah is set to "foo"
When I set the blah to "bar"
And I select "do not update frobnicator"
And I submit the form
Then the blah should be "foo"
Related
I need to analyse one http event value which should not be greater than 30mins. & 95% event should belong to this bucket. If it fails send the alert.
My first concern is to get the right metrics in /actuator/prometheus
Steps I took:
As in every http request event, I am getting one integer value called eventMinute.
Using micrometer MeterRegistry, I tried below code
// MeterRegistry meterRegistry ...
meterRegistry.summary("MINUTES_ANALYSIS", tags);
where tag = EVENT_MINUTE which receives some integer value in each
http event.
But this way, it floods the metrics due to millions of event.
Guide me a way please, i am beginner to this. Thanks!!
The simplest solution (which I would recommend you start with) would be to just create 2 counters:
int theThing = //getTheThing()
if(theThing > 30) {
meterRegistry.counter("my.request.counter.abovethreshold").inc()
}
meterRegistry.counter("my.request.counter.total").inc()
You would increment the counter that matches your threshold and another that tracks all requests (or reuse another meter that does that for you).
Then it is simple to setup a chart or alarm:
my_request_counter_abovethreshold/my_request_counter_total < .95
(I didn't test the code. It might need a tiny bit of tweaking)
You'll be able to do a similar thing with DistributionSummary by setting various SLOs (I'm not familiar with them to be able to offer one), but start with something simple first and if it is sufficient, you won't need the other complexity.
There are certain ways to solve this problem
1 ; here is a function which receives tags, name of metrics and a value
public void createOrUpdateHistogram(String metricName, Map<String, String> stringTags, double numericValue)
{
DistributionSummary.builder(metricName)
.tags(tags)
//can enforce slo if required
.publishPercentileHistogram()
.minimumExpectedValue(1.0D) // can take this based on how you want your distibution
.maximumExpectedValue(30.0D)
.register(this.meterRegistry)
.record(numericValue);
}
then it produce metrics like
delta_bucket{mode="CURRENT",le="30.0",} 11.0
delta_bucket{mode="CURRENT", le="+Inf",} 11.0
so as infinte also hold the less than value, so subtract the le=30 from le=+Inf
Another ways could be
public void createOrUpdateHistogram(String metricName, Map<String, String> stringTags, double numericValue)
{
Timer.builder(metricName)
.tags(tags)
.publishPercentiles(new double[]{0.5D, 0.95D})
.publishPercentileHistogram()
.serviceLevelObjectives(new Duration[]{Duration.ofMinutes(30L)})
.minimumExpectedValue(Duration.ofMinutes(30L))
.maximumExpectedValue(Duration.ofMinutes(30L))
.register(this.meterRegistry)
.record((long)timeDifference, TimeUnit.MINUTES);
}
it will only have two le, the given time and +inf
it can be change based on our requirements also it gives us quantile.
I'm trying to write a cucumber test for part of our application (I'm completely new to cucumber, and writing acceptance tests really), and I have a step in the test, which I want to do one of 2 different things. I want it to either check for a specific value, or check for a system default value.
This is what I came up with
Scenario Outline: English News
Given with the locale is set to '<language>'
When a user views the page
Then they see the <image> image
Examples:
| language | image |
| en-gb | default |
| fr | "french.png" |
This then hits one of 2 different step definitions,
#And("^they see the default image$")
public void defaultImage() throws Throwable {
// check for system default
}
#And("^they see the \"(.*)\" image$")
public void customImage(String image) throws Throwable {
// check for specific value from the input
}
Is this the correct way to do this? My TL has suggested that I should actually only have the one step def, and pass "default" as the input, and then do a conditional check inside the step def, like this:
#And("^they see the \"(.*)\" image$")
public void checkImage(String image) throws Throwable {
if ("default".equals(image)){
// check for system default
} else {
// check for specific value from the input
}
}
Which is the correct way to do this? Any help is greatly appreciated.
your default image must have a real name, right ? so why not validating its real name ? because "default" could be anything so not everyone may understand the same thing.
If you do this, indeed you need only one step def. I wouldn't put an if check, I would assert the real name. You can maybe add a comment in your example table saying that the first value is the default, so that it's clear for everyone in your team.
I have records that have an index attribute to maintain their position in relation to each other.
I have a plugin that performs a renumbering operation on these records when the index is changed or new one created. There are specific rules that apply to items that are at the first and last position in the list.
If a new (or existing changed) item is inserted into the middle (not technically the middle...just somewhere between start and end) of the list a renumbering kicks off to make room for the record.
This renumbering process fires in a new execution pipeline...We are updating record D. When I tell record E to change (to make room for D) that of course fires the plugin on update message.
This renumbering is fine until we reach the end of the list where the plugin then gets into a loop with the first business rule that maintains the first and last record differently.
So I am trying to think of ways to pass a flag to the execution context spawned by the renumbering process so the recursion skips the boundary edge business rules if IsRenumbering == true.
My thoughts / ideas:
I have thought of using the Depth check > 1 but that isn't a reliable value as I can't explicitly turn it on or off....it may happen to work but that is not engineering a solid solution that is hoping nothing goes bump. Further a colleague far more knowledgeable than I said that when a workflow calls a plugin the depth value is off and can't be trusted.
All my variables are scoped at the execute level so as to avoid variable pollution at the class level....However if I had a dictionary object, tuple, something at the class level and one value would be the thread id and the other the flag value then perhaps my subsequent execution context could check if the same owning thread id had any values entered.
Any thoughts or other ideas on how to pass context information to a new pipeline would be greatly appreciated.
Per Nicknow sugestion I tried sharedvariables but they seem to be going out of scope...:
First time firing post op:
if (base.Stage == EXrmPluginStepStage.PostOperation)
{
...snip...
foreach (var item in RenumberSet)
{
Context.ParentContext.SharedVariables[recordrenumbering] = "googly";
Entity renumrec = new Entity("abcd") { Id = item.Id };
#region We either add or subtract indexes based upon sortdir
...snip...
renumrec["abc_indexfield"] = TmpIdx + 1;
break;
.....snip.....
#endregion
OrganizationService.Update(renumrec);
}
}
Now we come into Pre-Op of the recursion process kicked off by the above post-op OrganizationService.Update(renumrec); and it seems based upon this check the sharedvariable didn't carry over...???
if (!Context.SharedVariables.Contains(recordrenumbering))
{
//Trace.Trace("Null Set");
//Context.SharedVariables[recordrenumbering] = IsRenumbering;
Context.SharedVariables[recordrenumbering] = "Null Set";
}
throw invalidpluginexception reveals:
Sanity Checks:
Depth : 2
Entity: ...
Message: Update
Stage: PreOperation [20]
User: 065507fe-86df-e311-95fe-00155d050605
Initiating User: 065507fe-86df-e311-95fe-00155d050605
ContextEntityName: ....
ContextParentEntityName: ....
....
IsRenumbering: Null Set
What are you looking for is IExecutionContext.SharedVariables. Whatever you add here is available throughout the entire transaction. Since you'll have child pipelines you'll want to look at the ParentContext for the value. This can all get a little tricky, so be sure to do a lot of testing - I've run into many issues with SharedVariables and looping operations in Dynamics CRM.
Here is some sample (very untested) code to get you started.
public static bool GetIsRenumbering(IPluginExecutionContext pluginContext)
{
var keyName = "IsRenumbering";
var ctx = pluginContext;
while (ctx != null)
{
if (ctx.SharedVariables.Contains(keyName))
{
return (bool)ctx.SharedVariables[keyName];
}
else ctx = ctx.ParentContext;
}
return false;
}
public static void SetIsRenumbering(IPluginExecutionContext pluginContext)
{
var keyName = "IsRenumbering";
var ctx = pluginContext;
ctx.SharedVariables.Add(keyName, true);
}
A very simple solution: add a bit field to the entity called "DisableIndexRecalculation." When your first plugin runs, make sure to set that field to true for all of your updates. In the same plugin, check to see if "DisableIndexRecalculation" is set to true: if so, set it to null (by removing it from the TargetEntity entirely) and stop executing the plugin. If it is null, do your index recalculation.
Because you are immediately removing the field from the TargetEntity if it is true the value will never be persisted to the database so there will be no performance penalty.
I have a textfield (lower level) a call a function that call a higher level form that contains a datafield to pick up a date and display it in my textfield lowerlevel.
The problem is I cannot get back to my textfield (lower level) since the datefield appears
public void formdatepicker() {
final javax.microedition.lcdui.Command CONFIRM_COMMAND
= new javax.microedition.lcdui.Command("OK",
javax.microedition.lcdui.Command.OK, 1);
javax.microedition.lcdui.Command CANCEL_COMMAND
= new javax.microedition.lcdui.Command("Cancel",
javax.microedition.lcdui.Command.CANCEL, 2);
final DateField datefield = new DateField("Pick a date", DateField.DATE);
form.append(datefield);
form.addCommand(CONFIRM_COMMAND);
form.addCommand(CANCEL_COMMAND);
form.setCommandListener(new CommandListener() {
public void commandAction(javax.microedition.lcdui.Command c, Displayable d) {
if (c == CONFIRM_COMMAND) {
Date date = datefield.getDate();
display.setCurrent(null);// try to hide the current form to get
}
}
});
Display.getInstance().getJ2MEDisplay().setCurrent(form);
Your mistake is wrong assumption about what setCurrent(null) does. Per your question and code snippet, it looks like you expect it to somehow show the screen that has been displayed prior to form. It doesn't, see the exaplanation in the API javadocs (available online):
The application may pass null as the argument to setCurrent(). This does not have the effect of setting the current Displayable to null; instead, the current Displayable remains unchanged. However, the application management software may interpret this call as a request from the application that it is requesting to be placed into the background...
If you want to use setCurrent(Displayable) to show some screen instead of current one, you need to pass this screen as an argument to setCurrent.
For the sake of completeness, note that there is another version of setCurrent that accepts two parameters, first of which is Alert, which works a bit differently, but it is not applicable in your case because you use Form not Alert.
I'm trying to wrote a pex test, and I noticed that it always was feeding a false value as one of the params that I wanted. My test looked like this (simplified: there are/were more params, but otherwise no different):
[PexMethod]
public void TestCtor(bool value)
{
ArbitraryType myType = new ArbitraryType(value);
}
I wanted to test a scenario where I would have pex do the exploration, ensuring that value would be true. I made another test that looked like this:
[PexMethod]
public void TestCtor(bool value)
{
Contract.Requires(value == true);
ArbitraryType myType = new ArbitraryType(value);
}
But when I have Pex explore that, it still spits in false to value and the test it generates "passes". If I put a line after the requirement saying Contract.Assert(!value); It'll create another test and pass true for value to fail the assertion.
The question is, why isn't Pex satisfying the code contract?
I'm not sure what Pex is going to do with Contracts in the test methods, but I can't see it being a Good Thing :)
If you want Pex to do this, the correct thing to do is use PexAssume.IsTrue(value).