DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • Mastering Time Series Analysis: Techniques, Models, and Strategies
  • Exploratory Testing Tutorial: A Comprehensive Guide With Examples and Best Practices
  • Microservices With Apache Camel and Quarkus
  • Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline

Trending

  • Mastering Time Series Analysis: Techniques, Models, and Strategies
  • Exploratory Testing Tutorial: A Comprehensive Guide With Examples and Best Practices
  • Microservices With Apache Camel and Quarkus
  • Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline
  1. DZone
  2. Software Design and Architecture
  3. Security
  4. How to Scope Scenarios with JBehave and Guice

How to Scope Scenarios with JBehave and Guice

Ryan Nelson user avatar by
Ryan Nelson
·
Jun. 05, 13 · Interview
Like (0)
Save
Tweet
Share
7.62K Views

Join the DZone community and get the full member experience.

Join For Free
If you use JBehave with a dependency injection framework such as Spring or Guice, you may quickly realize that scoping the Step classes gets a little tricky.  By default, both of those frameworks provide two basic scopes: instance (or prototype) scope, and singleton scope. 

Neither one of these options is great for use with JBehave.  Instance scope is a problem because JBehave then creates a new Step class for every step in a scenario, making it impossible to share state between steps without using static (global) state.  Singleton scope is a different side of the same problem: state ends up shared among all scenarios.  In either case, to make things work you must remember to clean up the global state after each scenario.

A simpler solution would be to implement a custom "scenario" scope.  I will show you how to do this for Guice below.

First, we need to define a new custom scope by implementing Guice'sScope interface.  This class will be a container that adds and manages our dependencies when the scope is entered, and removes them when the scope is exited.  This could be potentially daunting and error prone, but fortunately the Guice developers have provided us with a default calledSimpleScope, which does all this for us.  This class is sufficient for our needs, and you can copy it as-is straight into your source code.

Second, we need to tell JBehave when to actually create a new scope, and when to close the scope out.  Since we want to scope our dependencies to scenarios, we use JBehave's @BeforeScenario and @AfterScenario annotations to enter and exit each scope.  Note that we must inject our copy of SimpleScope, which is what actually manages the scoped dependencies.

 public class ScenarioContext { 




private SimpleScope scope; 




@Inject 
public ScenarioContext( @Named ( "scenarioScope" ) SimpleScope scope ) { 
this.scope = scope;
} 




@BeforeScenario 
public void beforeScenario() { 
scope.enter(); 
} 




@AfterScenario 
public void afterScenario() { 
scope.exit(); 
} 
} 

Third, much like the Singleton annotation, we need a binding annotation to inform Guice about how we'd like our step classes scoped.  We will use this new annotation to bind instances to our new SimpleScope class.  We create it simply like thus:

 import static java.lang.annotation.ElementType.METHOD; 
import static java.lang.annotation.ElementType.TYPE; 
import static java.lang.annotation.RetentionPolicy.RUNTIME; 




import java.lang.annotation.Retention; 
import java.lang.annotation.Target; 




import com.google.inject.ScopeAnnotation; 




@Target ( { TYPE, METHOD } ) 
@Retention ( RUNTIME ) 
@ScopeAnnotation 
public @interface ScenarioScope {} 

There are two parts to the final step.  The first is to actually bind our step classes to our new scope, which is accomplished simply by providing the class file to the binder using .in().  However, we also need to inform Guice about how to manage the SimpleScope container.

 public class AppModule extends AbstractModule { 
@Override 
protected void configure() { 
setUpScenarioScope(); 




bind( MySteps.class ).in( ScenarioScope.class ); 
} 




private void setUpScenarioScope() { 




bindScope( ScenarioScope.class, scenarioScope ); 




SimpleScope scenarioScope = new SimpleScope(); 
bind( SimpleScope.class ).annotatedWith( Names.named( "scenarioScope" ) ).toInstance( scenarioScope ); 
bind( ScenarioContext.class ).in( Singleton.class ); 
} 
} 

The setUpScenarioScope() method above does a couple of things:
  • informs Guice of our new scope, using bindScope()
  • creates an instance of our SimpleScope class for managing dependencies (we only need one)
  • ensures that instance can be injected into our JBehave-annotated context class
  • binds that context in the singleton scope
That's it!  All steps annotated for scenario scope will be able to share data within a single step class, while  guaranteeing a fresh set of steps for every new scenario.

Known issue: This approach is not currently compatible with jbehave-junit-runner library.  That library creates a special JBehave runner which formats the test results in a standard JUnit output, and it relies on a older copy of JBehave that causes a chicken-and-egg problem with Step creation.  A patch has been submitted to fix this, but to date it has not been incorporated into a release.  A workaround is to build from source and apply the patch manually, and make sure you are using JBehave 3.8+.
Dependency injection Annotation Inform Patch (computing) Container Framework Library Prototype Data (computing)

Published at DZone with permission of Ryan Nelson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Mastering Time Series Analysis: Techniques, Models, and Strategies
  • Exploratory Testing Tutorial: A Comprehensive Guide With Examples and Best Practices
  • Microservices With Apache Camel and Quarkus
  • Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: