Archive for the ‘automation’ Category
There is so much more that can be automated with Gherkin.
In the previous post, I announced the open sourcing of the gwen-interpreter project. In this post I will introduce the interpreter and evaluation engine concepts and describe the difference and relationship between them.
The Gwen interpreter translates Gherkin features into executable code. The code that each step is translated to is not defined in the interpreter itself, but rather in separate modules called evaluation engines. When a feature is executed, the interpreter delegates the processing of each step to a mixed in engine that you define or provide. This is necessary since evaluation varies across systems and it would be futile to try and code for every conceivable behavior in one implementation. For this reason Gwen abstracts the evaluation engine to support many implementations. In this way, you decide which engine to use based on the type of system you want to evaluate. For example, if you want to evaluate the behavior of a web application, then you can use our web engine. Each engine must prescribe a DSL and use at least one API to interact with a target system.
Engines can be defined to replicate any software process that is reproducible through one or more API’s.
There are many useful engines that can be built and they need not all be confined to just testing. Engines can be defined to automate, emulate, or simulate any process that is repeatable through software. Engines can also be built to generate data and other resources too.
- The interpreter reads Gherkin features and dispatches the processing of each step to a mixed in engine.
- Engines define the DSL and processing to create conditions, perform actions, and assert expectations on target systems.
Hopefully many engines will emerge from the community and be shared.
One platform for many types of automation.
Gherkin is a language for describing software behavior. Any software behavior. It makes sense to use it for evaluating software behavior too. But how can one evaluate any software behavior against any system with the one language?
A common language interpreter with an abstracted evaluation engine could be one way to do it.
This interpreter would accept Gherkin features as input and produce executing instructions as output. Specialised engines with specifically prescribed DSLs could be built and mixed in. The interpreter would support sequential or parallel execution. It would also produce evaluation reports and have a REPL console. It would provide all the necessary processing and tooling required to interpret Gherkin features and execute them. A public library of engines would emerge and be shared for everyone to download and use. The one interpreter would work with all of them.
It’s a simple idea that a colleague and I have been working on. We wrote it in Scala and open sourced it as a project called gwen.
Check it out and have a play. We have released several stable versions of our web engine here: https://github.com/gwen-interpreter/gwen-web/releases
Rules are made to be broken so that paradoxes can be created.
Maven is a handy tool and has a lot of available plugins. It adopts the convention over configuration philosophy and provides a standard build lifecycle out of the box. This makes it very easy to automate a build and release process without writing a single line of script. But there’s a catch! It only works if you do things the “maven way” and follow the maven rules.
Most projects are made up of one or more multiple smaller projects. In the maven world, such projects are called multi module projects. A multi module project has a parent project and one or more nested child projects known as modules. When you build the parent project the child projects are also built. The recommended maven way of structuring a multi module project is to mirror the parent child hierarchy using a nested project structure.
So maven recommends that you create a parent project that contains the child projects using a physical project structure like this:
workspace/parent/pom.xml workspace/parent/child1/pom.xml workspace/parent/child2/pom.xml
Modules are then declared in the parent POM like this:
<modules> <module>child1</module> <module>child2</module> </modules>
This was good for maven but it was is not good for eclipse. The eclipse IDE does not support nested projects. This was clearly a problem! I wanted to import all my projects (parent and children) into eclipse but the nested structure made this impossible. So I decided to use a flat project structure instead and moved all my child projects out of the parent project.
Now my parent and child projects were organised in a flat physical structure like this:
workspace/parent/pom.xml workspace/child1/pom.xml workspace/child2/pom.xml
And I then redefined the maven modules in the parent POM like this:
<modules> <module>../child1</module> <module>../child2</module> </modules>
Now I could import all my projects into eclipse. This worked well and life was good until I decided to use the maven release plugin to automate the release process. I learned the hard way that the release plugin only supports the nested project structure recommended by maven. Reverting back to the nested structure was not an option. I had broken a maven rule and was being punished for it! I needed a paradoxical solution that would support both the nested and flat structures at the same time. It was then that I realised that my parent POM was responsible for two things: POM inheritance and module composition. It served two “parental” roles. In one role it provided all the common properties, dependencies, plugins, and profiles to all children through inheritance and in the other it defined itself as the parent project of all child projects. In OO terms, this was akin to defining a superclass that contains a list of all its subclasess.
My parent POM had violated the single responsibility principle. So I decided to split it up into two separate parent POMs. I removed the modules declaration from the original POM in my parent project. This POM was now purely to be used for inheritance purposes only. All child POMs continued to reference this POM as the parent POM. Nothing changed there. I then created a new POM that inherited this modified POM and aggregated all the other child POMs. I placed this new top level POM file in the workspace root alongside all my existing projects. My flat project structure now had a top level POM file that defined all the child projects as modules.
The final project structure looked like this:
workspace/pom.xml workspace/parent/pom.xml workspace/child1/pom.xml workspace/child2/pom.xml
workspace/parent/pom.xml was inherited by all child POMs and also the top level
workspace/pom.xml. It was the parent POM for inheritance purposes. The top level
workspace/pom.xml aggregated all the child projects into one container project. It was the (root) parent POM for composition purposes. It defined the parent and child modules like this:
<parent> <groupId>?</groupId> <artifactId>?</artifactId> <version>?</version> <relativePath>parent/pom.xml</relativePath> </parent> <modules> <module>parent</module> <module>child1</module> <module>child2</module> </modules>
Both the maven release plugin and the eclipse IDE were happy with this structure. It was flat enough for eclipse and hierarchical enough for the maven release plugin.
Note: After experiencing and resolving this problem first hand I later discovered that the issue has already been reported and discussed here and mentioned at the very bottom of the maven eclipse plugin page. But I still cannot find any mention of this limitation on the maven release plugin page itself. I suspect that this is a well known issue in the maven community. If anyone is aware of any fixes or better solutions, please let me know. Interestingly also the title of this issue suggests that the problem has been fixed but the actual contents therein state otherwise.
Sample POM snippets – Posted on 22 Aug 2011 by request
workspace/pom.xml (The top level root POM)
<parent> <groupId>maven.demo</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>parent/pom.xml</relativePath> </parent> <groupId>maven.demo</groupId> <artifactId>root</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>parent</module> <module>child1</module> <module>child2</module> </modules>
workspace/parent/pom.xml (The parent POM)
<groupId>maven.demo</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging>
workspace/child1/pom.xml (The child1 POM)
<parent> <groupId>maven.demo</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../parent/pom.xml</relativePath> </parent> <groupId>maven.demo</groupId> <artifactId>child1</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging>
workspace/child2/pom.xml (The child2 POM)
<parent> <groupId>maven.demo</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../parent/pom.xml</relativePath> </parent> <groupId>maven.demo</groupId> <artifactId>child2</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>war</packaging>