Documentation of Cherry Framework
"The Agent remembers. The Agent uses Tools. The Agent performs Missions". - The Agent.
The Mission Pattern helps you modularise your code and create personas which describe business or functional interactions of software users. Users can also be clients of different layers of your software architecture.
In a Behavior Driven Development (BDD) project, we try to express the behaviors of our system in a Ubiquitous language - a Domain-Specific (DSL) one. Such a Ubiquitous language enables technical & non-technical people, domain experts or newbies to communicate within the same working environment using the same terms for exactly the same concepts. It is one of your means in your strive to bridge the communication gap. Mission Pattern enables software developers to do the same on code level as well when it comes to automating their (executable) requirements or specifications.
This pattern was inspired by the ScreenPlay Pattern (described here). It is effectively a simplification of the ScreenPlay Pattern whilst it doesn't restrict itself to just Page Objects or even Web Applications. On the contrary, Mission Pattern concepts are generic enough to describe any automatable User Journey or User Interaction with or without a web interface.
The first question, though, that springs to any developer's mind upon first hearing of a pattern is (quite rightfully): 'why should I use it? how it can improve my code?'. Let's find out!...
Every agile developer agrees that DRY and SOLID principles are a good guide to clean code. Mission Pattern is an enabler to apply exactly these principles in testing code. Some steps that people use are Page Objects, Helper classes, Services etc.
However, solid classes are not scalable enough. And if one is not careful, they can keep expanding to hundreds of lines of code. However, if you could store resources in an object and dynamically - even in a statically-typed programming language like Java - you could add functionality to them, in the shape of Single Responsibility Missions then... that would be great, right? That's exactly what Mission Pattern is all about: assisting you even further in your hard work of producing Clean, Scalable, Modularised, DRY & SOLID automation code.
Any developer who cares for automation & clean code practices and has also gone through the pain of refactoring (his/hers or other people's) automation code has a better insight in how essential it is to treat automation code as production code.
So then, how can we apply the Mission Pattern?
In this section we describe the main concepts of the pattern using the Cherry JVM Framework.
Agent is simply the Entity or Persona that plays a specific business or technical role when interacting with the layers (web or not) of your system. These very interactions come in the form of Missions. Feel free to use meaningful names for agents by using even persona names.
Mission is an interaction or a set of interactions with the System (be it a Web,Restful or other Resource) which can (optionally) return a result.
A Mission can be described in business terms, e.g.
In this example
registrationAsARegularCustomerWith is a static constructor of a Mission (e.g. we could have a
Registration interface and its implementation, the
WebRegistration class). This Mission can return a result (e.g. unique ID within registration confirmation) or not, but it definitely contains a set of sub-Missions (e.g. ClickOn, FillIn) etc.:
fillIn(dobField, with (dob))
[Note:] You will need cherry-web module to use the above in your project.
If Registration was happening over a Restful interface we could switch to a different implementation of Registration interface (e.g. called
RestfulRegistration) then the restful sub-Mission would be:
verifyAs(restfulUser).that(put('/register', requestWith(username,password,dob)), returnsStatusCode(200));
[Note:] You will need cherry-rest and cherry-junit modules to use the above rest interactions in your project.
Creating a Registration interface and then extending Mission
You can assign any type of Objects as tools to the Agent and use them in Missions:
agent.obtain(new FirefoxDriver(), databaseDriver);
and within a Mission you can use as follows:
WebDriver webDriver = agent.usingThe(WebDriver.class); DatabaseDriver dbDriver = agent.usingThe(DatabaseDriver.class);
Every Agent is instantiated with a Memory which enables an Agent to remember final or intermediary results of a Mission or other useful test data. The results can be of any type.
Store in Memory using a unique String key [in CoreMemory keys are Strings but you can create your own implementation of Memory
// I'm in a Database Mission String softwareVersion = retrieveVersionFromDB().accomplishAs(agent); // that's another syntax for accomplishing missions agent.keepsInMind("unique.key", softwareVersion);
and recall later on:
// I'm in a Web Mission now String softwareVersion = agent.recalls("unique.key", String.class); verifyAs(agent).that(landingPage.versionElement, hasText(softwareVersion));
In our example, landingPage is a WebScreen and versionElement is a WebScreenElement in cherry-webriver module. They are implementations of the following 2 concepts of Screens & ScreenElements.
Screens and ScreenElements
Screen is an Graphical Interface (Web, Swing etc.) which comprises of ScreenElements or other Screens, but doesn't contain any functionality. It's just a container describing the layout of your Graphical Interface (Web or Other). Also, ScreenFactory helps you create Screens. Examples can be found in later chapters for WebDriver and Java Swing applications.
Let's see all of the above in action using Java (including Java 8) at the following chapters.