Overview

Getting Started with Zucchini

3 Comments

What is Zucchini?

Zucchini is a new testing framework that uses a BDD-style domain-specific language (DSL). One of its focus areas is simplifying acceptance tests written with Selenium. It is not a replacement for JBehave or the Robot Framework, as you will see later on. This guide will give you a glimpse of Zucchini’s concepts by describing an example step by step.

Your First Zucchini Test

We are starting with this simple test class:

public class GettingStarted extends CommonStatements {
    @Test
    public void testCodecentricSearch() {
        given("I am on codecentric.de")
            .when("I type \"codecentric\" into the search box")
            .andWhen("I submit the search")
            .then("I see \"codecentric\" on the page")
            .end();
    }
}

This looks pretty easy, doesn’t it? But let’s examine this test for a moment:

  • This is obviously some kind of test. @Test suggests that this is a JUnit test, and that is indeed correct.
  • It seems like there is some kind of domain-specific language involved: given().when().andWhen().then().end().
  • "I am on codecentric.de" looks like some kind of initial situation.
  • "I type \"codecentric\" into the search box" and "I submit the search box" look like interactions that a user has with a website.
  • "I see \"codecentric\" on the page" looks like an expectation.

If you’ve made it so far, you already know 90% of the important stuff. But wait, we missed something, didn’t we? How does the test know what to do with these statements? Is there a complex language I have to learn before? And what is this CommonStatements class doing there? Okay, to be honest: I have held back some information. First of all, no, you don’t have to learn a new language. The statements in this test are placeholders for instructions that I will show you in a moment. And yes, CommonStatements plays a big role. But most importantly: This is a real test and it works perfectly. It will do what you expect it will do and there is missing in this class. The next section will describe the magic behind those statements.

The CommonStatements class

Magic

The previous section contained a simple test that navigates to codecentric.de, types “codecentric” into the search box, submits the search box and expects “codecentric” to be somewhere on the page – for example, as part of search results – afterwards. There seemed to be some magic involved since we have already ruled out that there is a complex language you have to learn. So what is the magic inside CommonStatements? I am sorry to disappoint you but there is no magic at all. This is most of the part that I have held back before:

public class CommonStatements {
    @Rule
    public WebFactRule onCodecentricRule = new WebFactRule(
        "I am on codecentric.de",
        onPage(url("http://www.codecentric.de"))
    );
 
    @Rule
    public WebStepRule searchCodecentricRule = new WebStepRule(
        "I type \"codecentric\" into the search box",
        type("codecentric").into(By.name("s"))
    );
 
    @Rule
    public WebStepRule submitSearchRule = new WebStepRule(
        "I submit the search",
        submit(By.name("s"))
    );
 
    @Rule
    public WebResultRule seeCodecentricOnPageRule = new WebResultRule(
        "I see \"codecentric\" on the page",
        see("codecentric")
    );
 
    @Rule
    public WebDriverExecutorRule webDriverExecutorRule = new WebDriverExecutorRule(
        new ChromeDriverProvider()
    );
}

Okay, now I’ve lost you. Let’s take baby steps towards becoming a Zucchini master.

Facts

We will start with the following code snippet as a first step:

@Rule
public WebFactRule onCodecentricRule = new WebFactRule(
    "I am on codecentric.de",
    onPage(url("http://www.codecentric.de"))
);

At first, you will notice that the statement that we have seen in our test case is part of a JUnit @Rule. I will not talk about JUnit @Rules here. If you don’t already know about this concept, you might want to go to the documentation before you continue.

The second part of the so called WebFactRule is onPage(url("http://www.codecentric.de")). Both, onPage() and url() are statically imported methods.

onPage() returns a WebFact. Basically, a fact is something you expect to be part of the initial state of a test. Actually, you don’t want to test facts. You take them for granted. Of course, Zucchini will detect if facts are broken and your test will fail if they are. If you have worked with Behavior Driven Development (BDD) before, you’re already familiar with Given, When, and Then. Zucchini calls atomic statements describing the initial state (Given) facts. Now, onPage() does not return Fact but WebFact. Web facts are specialized facts for web testing purposes. WebFact is just the interface for all types of web-specialized facts. The actual type of the object returned by onPage() is OnPageFact. All fact implementations describe how Zucchini can establish them. The OnPageFact knows how to open a specific page.

So, why do you need url(), you might ask. OnPageFact is more powerful than you need to know for the moment (in case you are curious: it supports Page Objects). The OnPageFact does not work on URLs directly but on something like a wrapper. For the sake of simplicity, let’s say url() takes a URL and wraps it in an object. I guess, we can take a step back and look at the previous code snippet again:

  • The WebFactRule is a JUnit @Rule that registers a fact.
  • The example above uses "I am on codecentric.de" as a name – no magic involved!
  • The fact of this example is able to open http://www.codecentric.de in a browser.

Steps

While growing up and learning more, baby steps become bigger. So let’s take a bigger code snippet:

@Rule
public WebStepRule searchCodecentricRule = new WebStepRule(
    "I type \"codecentric\" into the search box",
    type("codecentric").into(By.name("s"))
);
 
@Rule
public WebStepRule submitSearchRule = new WebStepRule(
    "I submit the search",
    submit(By.name("s"))
);

We have seen facts in the previous section. Now, we will introduce steps. While facts describe the initial state of the test, steps describe what you want to do once the initial state has been established.

What’s new? Actually, not much. Zucchini provides many useful methods that you can import statically to interact with pages, for example:

  • type(keys) types the given keys (text or a key combination) on the page,
  • type(keys).into(element) types the given keys into an element (e.g. a text input, text area, WYSIWYG editor, …),
  • select(element).index(index) selects the option with the index of a select element,
  • click(element) clicks on an element,
  • submit(element) submits an element, and many more.

Most of the web steps work on elements. These elements are described using Selenium’s By, for example:

  • By.id("html-element-id") describes the HTML element with the id attribute value html-element-id,
  • By.name("input-name") describes the HTML element with the name attribute value input-name,

Note: It is possible to create By locators that locate multiple elements. That’s perfectly fine. Sometimes you want to do something with multiple elements.

For more information on locating elements, please take a look at the Selenium WebDriver documentation.

By now, you should have deciphered the two rules above. However, I will summarize what you most likely already know:

  • Two new steps have been registered.
  • The first step is called "I type \"codecentric\" into the search box" and it simply types the text “codecentric” into a search box.
  • The second step is called "I submit the search" and it simply submits the search box (similar to hitting enter while still focussing the box).

Results

We are getting close to the end of this guide. By now, you should have figured out how to register facts that define the initial state and steps that describe how you want to interact with a page. This section will show you how you can check for page characteristics.

@Rule
public WebResultRule seeCodecentricOnPageRule = new WebResultRule(
    "I see \"codecentric\" on the page",
    see("codecentric")
);

A WebResult is a web-specific Result that checks whether the page state looks like you’d expect it to look. Zucchini provides some basic implementations, for example:

  • see(text) checks whether the text is present on the page,
  • input(element).isDisabled() checks whether the element is disabled.

The @Rule above can be described as follows:

  • A new result is registered.
  • The new result is called "I see \"codecentric\" on the page".
  • The result expects that “codecentric” is shown.

Now you know what facts, steps, and results are and you know how you can define them. Since Zucchini uses plain Java, you will be able to use all of your IDE’s auto-completion features. You don’t need an additional plug-in for your IDE or additional IDE configuration.

Executing Tests

The last part of the CommonStatements class is this:

@Rule
public WebDriverExecutorRule webDriverExecutorRule = new WebDriverExecutorRule(
    new ChromeDriverProvider()
);

This guide focusses on Zucchini’s web components. You can use Zucchini for other types of tests but that is a whole other story. I tell you this because different types of tests require different types of Executors.

The @Rule above registers a web-specific Executor that uses the Selenium WebDriver API internally. Selenium can run in multiple browsers so we need to tell the executor which browser to use. This example uses Chrome. You might want to use HtmlUnit instead for headless testing. I’ll leave you to it.

Dig Deeper

This short guide introduced parts of Zucchini which is a lean testing framework that uses a BDD-style DSL. You have learned how to write simple Zucchini web tests and I have shown you the basic concepts behind Zucchini. Here are some suggestions in case you want to dig deeper into Zucchini:

Post by Alexander Müller

Unbequeme Wahrheiten

More content about Agile Testing

Kommentare

  • Tomek

    nice, really nice!

    Could you please provide a snippet of how you pass parameters? I mean, what about “I am on page {xyz}” which should result in onPage(url(“xyz”))

    • Alexander Müller

      25. July 2014 von Alexander Müller

      Currently, there is no support for passing parameters. I thought about that but I didn’t came up with a good way to implement it forthrightly. But you’re right, this is certainly an important feature. I’ve created an issue for this:

      https://github.com/codecentric/zucchini/issues/8

      Of course, anybody is invited to improve Zucchini.

    • Alexander Müller

      4. August 2014 von Alexander Müller

      Variable substitution has been implemented and will be available with the next release. You might want to take a look at the examples project to see how you can use this feature.

Comment

Your email address will not be published. Required fields are marked *