Cucumber-JVM+Selenium+JUnit Toy released v1.2

Cheers! Toy project baselined to v1.2 and all pending issues resolved.

https://github.com/maxwu/cucumber-java-toy

Github Link

Brief

The target of this demo project is to show and refresh a general approach of BDD and experience the Gherkin specs as a communication tool on story definition and how to map it to JUnit case scope. It started on Monday from scratch and baselined Friday morning on schedule. Crtitial issues resolved were recorded on Github issue board, too. I recorded hints and tips in the readme markdown page. Here is a paper of note about the thoughts captured during the fast adaption phase.

There is another post about tips on PageObject design in web testing. This post is on general practice with Gherkin spec and JUnit.

Tips to Entry Level Cucumber Learners

  • First of first, Cucumber is a collaboration tool, especially in the situation to cowork with people from non-technical background on drafting specifications together. Then developers and testers also work on the "glue" part to test the real things. Most of the scenarios are not purely verified with JVM (or JS, whatever Cucumebr implementation). The test still needs to work through some third party libraries to test, as what request lib for RESTful interface, and, Selenium lib for Web Interaction test. Refer to the slides.

  • Readers migrating from Robot Framework or Junit, the suggestion is to carefully read the doc or code of @Before and @After. The test is against features instead of against implemented class (the process described as mentionnd on the six Cucumber steps). It just verifies the features by seaching for Gherkin matching ("public" for Java) functions and executing them to form a report. Therefore, no matter whether the test method is executed, the @Before annotated methods are invoked at every scenarios by default. However, test classes are instantiated right before the first step method call or the first hooked method call. In short, step definitions and hooks are global conceptually.

Scan and regiser the StepDefinition and hooks with below code logics:

public void scan(JavaBackend javaBackend, List<String> gluePaths) {
for (String gluePath : gluePaths) {
for (Class<?> glueCodeClass : classFinder.getDescendants(Object.class, packageName(gluePath))) {
while (glueCodeClass != null && glueCodeClass != Object.class && !Utils.isInstantiable(glueCodeClass)) {
// those can't be instantiated without container class present.
glueCodeClass = glueCodeClass.getSuperclass();
}
if (glueCodeClass != null) {
for (Method method : glueCodeClass.getMethods()) {
scan(javaBackend, method, glueCodeClass);
}
}
}
}
}

Adding hook and implictly sort the @Before hook with a customized comparator (to support Annotation parameter "order" (default to 10,000).

void addHook(Annotation annotation, Method method) {
if (objectFactory.addClass(method.getDeclaringClass())) {
if (annotation.annotationType().equals(Before.class)) {
String[] tagExpressions = ((Before) annotation).value();
long timeout = ((Before) annotation).timeout();
glue.addBeforeHook(new JavaHookDefinition(method, tagExpressions, ((Before) annotation).order(), timeout, objectFactory));
} else {
// ...@After hook...
}
}
}

It is not to walk thru classes and verify the annotated methods. Actually it has nothing to do with Unit Test although it is often to see JUnit as a test suite organization framework (for Gherkin feature test).

The hook execution is actually not related to how the classes are organized if default Object Factory is taken (instead of others like PicoContainer).

public void runBeforeHooks(Reporter reporter, Set<Tag> tags) {
runHooks(glue.getBeforeHooks(), reporter, tags, true);
}

public void runAfterHooks(Reporter reporter, Set<Tag> tags) {
runHooks(glue.getAfterHooks(), reporter, tags, false);
}

Note0: Official solution is to use @tags to separate "global" concepts of hooks and step methods.

Note1: One possible way to avoid redundant is to insert a customized annotation, e.g. GreenHook on class and thru that add lazily delay the invokation of @Before hooks untill the first "declared" method (not inherited, not constructor, no matter if it is from the same instanace) is processed with AspectJ.
Needs to code a test to verify.

Note2: AspectJ in test could be a separate topic for future.

  • Readers new to Cucumber, the tips is to understand Gherkin is an executable spec, therefore the implict activities shall be clarified when thinking about turning to this BDD approach.

  • Moving to Travis-CI and CircleCI is pretty a happay journey. However, we shall walk thru the environmental elements first as the OS, Browser version, special variables, et. The Selenium Web Driver could be well managed with WebManagerDriver lib.

    • Travis-CI:

    • Circle CI:

    • CodeCov:

  • Having code coverage metrics with codecov cloud service will simply save your time.

  • Reach out to BDD life and take it as a way to keep concentrated on valuable logics. Like the way to live with MarkDown, --"less is more". If we keep our mind focus on the valuable logics instead of being interrupted by checking those "sudden" or "interesting" things on the branch path to valuable delivery, then the productivity and consitency could have a chance to step over in a better position.

    • Keep a markdown format notes, as README.md in github project;
    • Be familiar with the format and make sure taking notes won't disattract your mind;
    • Google search around a technical issue is fine. However, we shall keep it fast and only for occassional and easy problems. Leave the refactor and structural issues to the notes and set a fixed time slot to process this "inbox" list. Keep only one window of browser with google/stakeoverflow, or, just search with Alfred.
  • Avoid (long) discussion with social network during the dedicated hour. Dedicated hour can be in the moring, or, the mid-night. It lasts for one hour and during this hour, only preplaned stories are considered.

The procedure with executable Gherkin specification via Cucumber:

6 Steps with Cucumber

Then the Red-Green-Refactor cycle starts to run. Cucumber provides a way to communicate between business and technologies, not propagation, not just collection, but a real communication. Executable spec means the specs are living as a guard or as rails. However, there are still pains and difficulties thought of during this practice.

  • For BDD, the case design or test design is a key from beginning to the end.
    • The case shall represent specs as business examples.
    • What else? the test shall also cover traditional test design chapters:
      • These techniques include: border identification, equivalence division, branch detection, fuzzer, Orthogonal Array, et.
    • Check: whether the test can pass only with given logics. Which means, if there is a future code change on concerned logics, the test is effecient and effective enough to detect with a signal (of failure or execution ignore).

Have fun and happy test.

Update Logs

[Updated Feb-23]: Update snapshot with http://jenkins.maxwu.me

[Updated Feb-09]: Add a missing sentence of concept description.

[Updated Jan-30]: Append a brief summary of red-green-refactor cycle.

[Updated Jan-14]: Add <More> mark into post source.

[Updated Jan-15]: Add thoughts paragraph-1 and refer to online slides link. Quote the JaveBack

[EOF]