I want to generate a report from JBehave that just lists the name of each scenario and a PASS/FAIL status. Bonus points if it gives a PASS/FAIL status for a story based on the the scenario results (if all scenarios pass the story passes). Something like:
PASS: Story: Build a widget.
PASS: Scenario: Build a normal widget.
PASS: Scenario: Build a custom widget.
FAIL: Story: Test a widget.
PASS: Scenario: Test a normal widget.
FAIL: Scenario: Test a custom widget.
Text is preferred but I can work with other formats.
This post:
Additional logging JBehave
shows how to use a StoryReporter to capture pass/fail for individual steps, but going through the interface I can't see how to capture the final status of a single scenario.
A commenter later in the same post mentions that there are several view genaration examples in the source distribution. If someone can give more specific pointers to which of the examples do this that would help too.
The StoryReporter code below should do what you are looking for. It keeps track of each scenario and the pass/fail status of each step in the scenario. If any step fails, then the scenario is failed. If any scenario fails, then the story is marked as failed. At the end of the story it logs the results.
public class MyStoryReporter implements org.jbehave.core.reporters.StoryReporter {
private Story runningStory;
private boolean runningStoryStatus;
private String runningScenarioTitle;
private boolean runningScenarioStatus;
private List<ScenarioResult> scenarioList;
private Log log = LogFactory.getLog(this.getClass());
private class ScenarioResult {
public String title;
public boolean result;
public ScenarioResult(String title, boolean result) {
this.title = title;
this.result = result;
}
}
public void beforeStory(Story story, boolean b) {
runningStory = story;
runningStoryStatus = true;
scenarioList = new ArrayList<>();
}
public void afterStory(boolean b) {
String storyPrefix = runningStoryStatus ? "PASS: STORY: " : "FAIL: STORY: ";
log.info(storyPrefix + runningStory.getName() + ".");
String scenarioPrefix;
for (ScenarioResult scenario : scenarioList) {
scenarioPrefix = scenario.result ? " PASS: SCENARIO: " : " FAIL: SCENARIO: ";
log.info(scenarioPrefix + scenario.title + ".");
}
}
public void beforeScenario(String s) {
runningScenarioTitle = s;
runningScenarioStatus = true;
}
public void afterScenario() {
scenarioList.add(new ScenarioResult(runningScenarioTitle, runningScenarioStatus));
runningStoryStatus = runningStoryStatus && runningScenarioStatus;
}
public void failed(String s, Throwable throwable) {
runningScenarioStatus = false;
}
Related
Summary: I am hoping to use Maui's builder.Services to resolve services in view models. But I don't understand how to do so.
I could create my own IServiceProvider, but I am hoping to avoid the needed boilerplate code, so seek a "standard Maui" solution.
I added the following line to MauiProgram.CreateMauiApp:
builder.Services.AddSingleton<IAlertService, AlertService>();
And the corresponding declarations (in other files):
public interface IAlertService
{
// ----- async calls (use with "await") -----
Task ShowAlertAsync(string title, string message, string cancel = "OK");
Task<bool> ShowConfirmationAsync(string title, string message, string accept = "Yes", string cancel = "No");
}
internal class AlertService : IAlertService
{
// ----- async calls (use with "await") -----
public Task ShowAlertAsync(string title, string message, string cancel = "OK")
{
return Application.Current.MainPage.DisplayAlert(title, message, cancel);
}
public Task<bool> ShowConfirmationAsync(string title, string message, string accept = "Yes", string cancel = "No")
{
return Application.Current.MainPage.DisplayAlert(title, message, accept, cancel);
}
}
Then in my BaseViewModel class:
internal class BaseViewModel
{
protected static IAlertService AlertSvc = ??? GetService (aka Resolve) ???
public static void Test1()
{
Task.Run(async () =>
await AlertSvc.ShowAlertAsync("Some Title", "Some Message"));
}
}
Question: How fill AlertSvc with the service registered in MauiProgram?
CREDIT: Based on a suggested "DialogService" in some SO discussion or Maui issue. Sorry, I've lost track of the original.
All the dependencies will be provided through the IServiceProvider implementation that is part of .NET MAUI. Luckily, the IServiceProvider itself is added to the dependency injection container as well, so you can do the following.
Add what you need to your dependency injection container in the MauiProgram.cs:
builder.Services.AddSingleton<IStringService, StringService>();
builder.Services.AddTransient<FooPage>();
For completeness, my StringService looks like this:
public interface IStringService
{
string GetString();
}
public class StringService : IStringService
{
public string GetString()
{
return "string";
}
}
Then in your FooPage, which can also be your view model or anything of course, add a constructor like this:
public FooPage(IServiceProvider provider)
{
InitializeComponent();
var str = provider.GetService<IStringService>().GetString();
}
Here you can see that you resolve the service manually through the IServiceProvider and you can call upon that. Note that you'll want to add some error handling here to see if the service actually can be resolved.
I am currently using Azure notification hub(FCM) to send one-one notification to user as well as notification to group of users by using tags(5000 - 10000 users at a time) .
Now while sending notification to group , I want some personalization like:
Hi ABC<$(firstname of user1)>, here is new AAAAA for you today.
Hi XYZ<$(firstname of user2)>, here is new AAAAA for you today.
.
.
Hi ZZZ<$(firstname of user5000)>, here is new AAAAA for you today.
I read that this is possible by using push variables with native registartion /installation sdk.
Ref:https://azure.microsoft.com/en-in/blog/updates-from-notification-hubs-independent-nuget-installation-model-pmt-and-more/
But I could not find any option in registration/installation Java SDK to set these values .
Registration registration = new FcmRegistration(id, token);
registration.getTags().add(tagname);
hub.createRegistration(registration);
Installation installation = new Installation(name);
installation.setPushChannel(token);
installation.setPlatform(NotificationPlatform.Gcm);
installation.addTag(tagname);
hub.createOrUpdateInstallation(installation);
Any help is really appreciated , otherwise for group notification I have to send notification for each user via iteration and that defeats benefit of using tags and getting the job done in just 1 hub API call.
You are correct - this is exactly what ANH templates are for. You can read this blog post about them for some background knowledge. Essentially, once you've created a template you can do a template send operation that provides just the values that need to be injected. i.e. Your Installation record will have set the appropriate body:
"Hi $(firstname), here is new $(subject) for you today."
and your send operation provides the values to inject:
{
"firstname": "ABC",
"subject": "AAAAA"
}
Also, make sure to specify the correct tags to scope the audience, in this case something like "ABC" to specify the user, and "new-daily" to specify which templates should be used.
Another trick, you can skip a layer of tag management and send fewer requests by embedding the $(firstname) in the template itself.
"Hi ABC, here is new $(subject) for you today."
Because templates are stored per device, each device can have a separate name embedded in it, reducing the number of tags you need to tinker with. This would make the body you send just:
{
"subject": "AAAAA"
}
and you only need to scope with the tag "new-daily".
Looks like you're on the right track with templating. When you embed an expression into surrounding text, you're effectively doing concatenation, which requires the expression to be surrounded in { }. See documentation about template expression language using Azure Notification Hubs where it states "when using concatenation, expressions must be wrapped in curly brackets."
In your case, I think you want something along the lines of:
...
{"title":"{'Seattle Kraken vs. ' + $(opponent) + ' starting soon'}",...}
...
Thanks a lot I got it working by extending the API classes on my own in following manner as per the blog suggested.
package com.springbootazure.controller;
import java.util.Map;
import org.apache.commons.collections.map.HashedMap;
import com.google.gson.GsonBuilder;
import com.windowsazure.messaging.FcmRegistration;
public class PushRegistration extends FcmRegistration {
private static final String FCM_NATIVE_REGISTRATION1 = "<?xml version=\"1.0\" encoding=\"utf-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\"><content type=\"application/xml\"><GcmRegistrationDescription xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.microsoft.com/netservices/2010/10/servicebus/connect\">";
private static final String FCM_NATIVE_REGISTRATION2 = "<GcmRegistrationId>";
private static final String FCM_NATIVE_REGISTRATION3 = "</GcmRegistrationId></GcmRegistrationDescription></content></entry>";
private Map<String, String> pushVariables = new HashedMap();
public PushRegistration() {
super();
}
public PushRegistration(String registrationId,
String fcmRegistrationId, Map<String, String> pushVariables) {
super(registrationId, fcmRegistrationId);
this.pushVariables = pushVariables;
}
public PushRegistration(String fcmRegistrationId, Map<String, String> pushVariables) {
super(fcmRegistrationId);
this.pushVariables = pushVariables;
}
#Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result
+ ((pushVariables == null) ? 0 : pushVariables.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PushRegistration other = (PushRegistration) obj;
if (pushVariables == null) {
if (other.pushVariables != null) {
return false;
}
} else if (!pushVariables.equals(other.pushVariables)) {
return false;
}
return true;
}
protected String getPushVariablesXml() {
StringBuilder buf = new StringBuilder();
if (!tags.isEmpty()) {
buf.append("<PushVariables>");
buf.append(new GsonBuilder().disableHtmlEscaping().create().toJson(pushVariables));
buf.append("</PushVariables>");
}
return buf.toString();
}
#Override
public String getXml() {
return FCM_NATIVE_REGISTRATION1 +
getTagsXml() +
getPushVariablesXml() +
FCM_NATIVE_REGISTRATION2 +
fcmRegistrationId +
FCM_NATIVE_REGISTRATION3;
}
}
And afterwards , register a token using :
Map<String, String> pushVariables = new HashMap<>();
pushVariables.put("firstname", "Gaurav");
pushVariables.put("lastname", "Aggarwal");
Registration registration = new PushRegistration(name, token, pushVariables);
if (registration == null) {
registration = new FcmRegistration(name, token);
}
registration.getTags().add(tagname);
registration.getTags().add(category);
hub.createRegistration(registration);
And then send notification like:
Notification n = Notification.createFcmNotifiation("{\n" +
" \"notification\" : {\n" +
" \"body\" : \"{ $(firstname) + ' starting soon'}\",\n" +
" \"title\" : \"test title\"\n" +
" }\n" +
"}");
hub.sendNotification(n, tagname);
I need to recollect some data calling to a method is connecting to a webservice.
problem: Imagine I need to update the content text of a label control according to this remote gathered information. Until all this data is recollected I'm not going to be able to show the label.
desired: I'd like to first show the label with a default text, and as I'm receiving this information I want to update the label content (please, don't take this description as a sucked code, I'm trying to brief my real situation).
I'd like to create an observable sequence of these methods. Nevertheless, these method have not the same signature. For example:
int GetInt() {
return service.GetInt();
}
string GetString() {
return service.GetString();
}
string GetString2 {
return service.GetString2();
}
These methods are not async.
Is it possible to create an observable sequence of these methods?
How could I create it?
Nevertheless, which's the best alternative to achieve my goal?
Creating custom observable sequences can be achieved with the Observable.Create. An example using your requirements is shown below:
private int GetInt()
{
Thread.Sleep(1000);
return 1;
}
private string GetString()
{
Thread.Sleep(1000);
return "Hello";
}
private string GetString2()
{
Thread.Sleep(2000);
return "World!";
}
private IObservable<string> RetrieveContent()
{
return Observable.Create<string>(
observer =>
{
observer.OnNext("Default Text");
int value = GetInt();
observer.OnNext($"Got value {value}. Getting string...");
string string1 = GetString();
observer.OnNext($"Got string {string1}. Getting second string...");
string string2 = GetString2();
observer.OnNext(string2);
observer.OnCompleted();
return Disposable.Empty;
}
);
}
Note how I have emulated network delay by introducing a Thread.Sleep call into each of the GetXXX methods. In order to ensure your UI doesn't hang when subscribing to this observable, you should subscribe as follows:
IDisposable subscription = RetrieveContent()
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(text => Label = text);
This code uses the .SubscribeOn(TaskPoolScheduler.Default) extension method to use a TaskPool thread to start the observable sequence and will be blocked by the calls the Thread.Sleep but, as this is not the UI thread, your UI will remain responsive. Then, to ensure we update the UI on the UI thread, we use the ".ObserveOn(DispatcherScheduler.Current)" to invoke the updates onto the UI thread before setting the (data bound) Label property.
Hope this is what you were looking for, but leave a comment if not and I'll try to help further.
I would look at creating a wrapper class for your service to expose the values as separate observables.
So, start with a service interface:
public interface IService
{
int GetInt();
string GetString();
string GetString2();
}
...and then you write ServiceWrapper:
public class ServiceWrapper : IService
{
private IService service;
private Subject<int> subjectGetInt = new Subject<int>();
private Subject<string> subjectGetString = new Subject<string>();
private Subject<string> subjectGetString2 = new Subject<string>();
public ServiceWrapper(IService service)
{
this.service = service;
}
public int GetInt()
{
var value = service.GetInt();
this.subjectGetInt.OnNext(value);
return value;
}
public IObservable<int> GetInts()
{
return this.subjectGetInt.AsObservable();
}
public string GetString()
{
var value = service.GetString();
this.subjectGetString.OnNext(value);
return value;
}
public IObservable<string> GetStrings()
{
return this.subjectGetString.AsObservable();
}
public string GetString2()
{
var value = service.GetString2();
this.subjectGetString2.OnNext(value);
return value;
}
public IObservable<string> GetString2s()
{
return this.subjectGetString2.AsObservable();
}
}
Now, assuming that you current service is called Service, you would write this code to set things up:
IService service = new Service();
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService`
var subscription =
Observable
.Merge(
wrapped.GetInts().Select(x => x.ToString()),
wrapped.GetStrings(),
wrapped.GetString2s())
.Subscribe(x => label.Text = x);
IService wrappedService = wrapped;
Now pass wrappedService instead of service to your code. It's still calling the underlying service code so no need for a re-write, yet you still are getting the observables that you want.
This is effectively a gang of four decorator pattern.
I have a web service posting Gherkins stories to a back-end and would like to load those stories into configuration as a string without having to save them as a file.
Can this be accomplished?
You need to implement your custoom story loader that will collect stories from the web service and pass them to JBehave.
You need also use a GherkinStoryParser to translate stories from Gherking format to JBehave format.
An example configuration might look like in the following example.
A custom story loader that retrieves stories from a map of strings:
public class MyStoryLoader implements StoryLoader {
private Map<String,String> stories;
public MyStoryLoader( Map<String,String> storiesToLoad){
this.stories = storiesToLoad;
}
public String loadStoryAsText(String storyName) {
return stories.get( storyName );
}
}
Some class that collects stories from the web service and return them as a map with unique story names and story bodies:
public class StoryCollectorFromWebService {
private final static String storyTemplate = "Feature: A story that is saved in the string\n"
+ "\n"
+ "Scenario: Read the scenario from the string\n"
+ "\n"
+ "Given There is some story named ${name} saved in the string\n"
+ "When I run this story named ${name}\n"
+ "Then I can see it's results";
// This is a method that collects stories from the Web Service and saves them in a map of strings
public Map<String,String> getStoriesFromWebService(){
Map<String,String> storiesFromWebService = new HashMap<String,String>();
String storyNames[] = {"A","B","C","ABC","Some story", "Another story"};
for(String storyName: storyNames)
storiesFromWebService.put( storyName, storyTemplate.replace("${name}", storyName));
return storiesFromWebService;
}
}
and sample configuration to run these stories using our StoryLoader and GherkinStoryParser:
public class RunAs_JUnitStories extends JUnitStories {
public RunAs_JUnitStories() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).useThreads(1).useStoryTimeoutInSecs(60);
}
Map<String,String> storiesFromWebService = new StoryCollectorFromWebService().getStoriesFromWebService();
#Override
protected List<String> storyPaths() {
return new ArrayList<String>( storiesFromWebService.keySet());
}
#Override
public Configuration configuration() {
Class<? extends Embeddable> embeddableClass = this.getClass();
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory examplesTableFactory = new ExamplesTableFactory(new LocalizedKeywords(), new LoadFromClasspath(embeddableClass), parameterConverters);
parameterConverters.addConverters(new DateConverter(new SimpleDateFormat("yyyy-MM-dd")),
new ExamplesTableConverter(examplesTableFactory));
return new MostUsefulConfiguration()
// Use custom story loader
.useStoryLoader(new MyStoryLoader( storiesFromWebService ))
// Use Gherkin parser
.useStoryParser( new GherkinStoryParser() )
.useStoryReporterBuilder(new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
.withDefaultFormats()
.withMultiThreading(true)
.withFormats(CONSOLE, TXT, HTML, XML))
.useParameterConverters(parameterConverters);
}
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new MySteps());
}
}
Here is a link to a working example: https://github.com/kordirko/TestJBB
You can try import it into Eclipse and play with it, but I apologize if something goes wrong,
It's my first project on github, I'am still learning how to do it :)
I am having two Methods in Unit Test case where First Insert Records into Database and Second retrieves back data. I want that input parameter for retrieve data should be the id generated into first method.
private int savedrecordid =0;
private object[] SavedRecordId{ get { return new object[] { new object[] { savedrecordid } }; } }
[Test]
public void InsertInfo()
{
Info oInfo = new Info();
oInfo.Desc ="Some Description here !!!";
savedrecordid = InsertInfoToDb(oInfo);
}
[Test]
[TestCaseSource("SavedRecordId")]
public void GetInfo(int savedId)
{
Info oInfo = GetInfoFromDb(savedId);
}
I know each test case executed separately and separate instance we can't share variables across test methods.
Please let me know if there is way to share parameters across the test cases.
The situation you describe is one of unit tests' antipatterns: unit tests should be independent and should not depend on the sequence in which they run. You can find more at the xUnit Patterns web site:
Unit test should be implemented using Fresh Fixture
Anti pattern Shared Fixture
And both your unit tests have no asserts, so they can't prove whether they are passing or not.
Also they are depend on a database, i.e. external resource, and thus they are not unit but integration tests.
So my advice is to rewrite them:
Use mock object to decouple from database
InsertInfo should insert info and verify using the mock that an appropriate insert call with arguments has been performed
GetInfo should operate with a mock that returns a fake record and verify that it works fine
Example
Notes:
* I have to separate B/L from database operations…
* … and make some assumptions about your solution
// Repository incapsulates work with Database
public abstract class Repository<T>
where T : class
{
public abstract void Save(T entity);
public abstract IEnumerable<T> GetAll();
}
// Class under Test
public class SomeRule
{
private readonly Repository<Info> repository;
public SomeRule(Repository<Info> repository)
{
this.repository = repository;
}
public int InsertInfoToDb(Info oInfo)
{
repository.Save(oInfo);
return oInfo.Id;
}
public Info GetInfoFromDb(int id)
{
return repository.GetAll().Single(info => info.Id == id);
}
}
// Actual unittests
[Test]
public void SomeRule_InsertInfo_WasInserted() // ex. InsertInfo
{
// Arrange
Info oInfo = new Info();
oInfo.Desc = "Some Description here !!!";
var repositoryMock = MockRepository.GenerateStrictMock<Repository<Info>>();
repositoryMock.Expect(m => m.Save(Arg<Info>.Is.NotNull));
// Act
var savedrecordid = new SomeRule(repositoryMock).InsertInfoToDb(oInfo);
// Assert
repositoryMock.VerifyAllExpectations();
}
[Test]
public void SomeRule_GetInfo_ReciveCorrectInfo() // ex. GetInfo
{
// Arrange
var expectedId = 1;
var expectedInfo = new Info { Id = expectedId, Desc = "Something" };
var repositoryMock = MockRepository.GenerateStrictMock<Repository<Info>>();
repositoryMock.Expect(m => m.GetAll()).Return(new [] { expectedInfo }.AsEnumerable());
// Act
Info receivedInfo = new SomeRule(repositoryMock).GetInfoFromDb(expectedId);
// Assert
repositoryMock.VerifyAllExpectations();
Assert.That(receivedInfo, Is.Not.Null.And.SameAs(expectedInfo));
}
ps: full example availabel here