Git Product home page Git Product logo

funcy's Introduction

funcy

Page Driven Functional Tests for Play 2.3.x.

Introduction

Functional Test in Play 2.3.x are the best way to test web applications:

  • In standard web applications, you simply do not have really complex business logic. There is no point in using unit tests.
  • Selenium tests are hard to setup (even with Plays support), require explizit fixtures and they are very slow - too slow to be run before each commit.

Example: Booking a ticket is fairly easy: Simply write a row into a database. Whats the point of writing a unit test for that?

Building the booking form, receiving the request, validating user input, creating the ticket, sending the confirmation mail and displaying the confirmation page, on the other hand, is quite a complex process.

But testing it through selenium is hard and , if you run into the trap of recording your test cases, very prone to changes of the underlying software. Using Page Driven Play 2.3.x Functional Tests provided by funcy, you can:

  • Write your tests as simple unit tests
  • Check results by accessing resulting web page doms or the database directly
  • Run them very fast against an in-memory database.

Consider this example:

@Test
public void testBooking() {
    IndexPage indexPage = new IndexPage();
    EventPage eventPage = indexPage.clickEvent("Sidney Opera");
    BookingPage bookingPage = eventPage.book("2012/05/07");
    ConfirmationPage confirmationPage = bookingPage.book();

    List<Booking> bookings = Booking.all();
    Assert.assertEquals("#bookings", 1, bookings.size());
}

Installation

Using build.sbt:

In your build.sbt add the dependencies. Use the test scope, because funcy is not required at runtime. You have to include the dependency for jsoup as well, because I did not yet succeed in building the module so that this dependency is transported to the app in test scope (solution, anybody?).

Don't forget to add my module repository as well:

resolvers += Resolver.url("Edulify Repository", url("http://edulify.github.io/modules/releases/"))(Resolver.ivyStylePatterns)

libraryDependencies ++= Seq(
    "funcy" %% "funcy" % "0.3" % "test"
)  

Using project/Build.scala:

In your Build.scala add the dependencies. Use the test scope, because funcy is not required at runtime. You have to include the dependency for jsoup as well, because I did not yet succeed in building the module so that this dependency is transported to the app in test scope (solution, anybody?).

Don't forget to add my module repository as well:

val appDependencies = Seq(
  "funcy" %% "funcy" % "0.3" % "test"
)

val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
    resolvers += Resolver.url("Edulify Repository", url("http://edulify.github.io/modules/releases/"))(Resolver.ivyStylePatterns)
)

Page

Create a subclass of Page for each page of your application. Consider the following example:

package pages;

import play.mvc.Result;
import funcy.Form;
import funcy.Page;

public class IndexPage extends Page {

    public IndexPage(Result result) {
        super(result, "/");
    }

    public IndexPage save(String msg) {
        Form form = form(0);
        form.set("test", msg);
        return new IndexPage(form.submitName("Save"));
    }

    public IndexPage clickReload() {
        return new IndexPage(clickName("Reload"));
    }
}

Typically a Page is constructed from a play.mvc.Result. The super-constructor expects a regexp additionally. The current URL is matched against this URL to assert whether the test is on the right page.

Your Page class should exhibit a public method for each action a user can perform on the page. That is the core of the Page Driver pattern: Create an abstract model of the page under test so that changes do not affect the test at all or can be represented by a change of the Page Drivers public contract, which is obvioulsy under good control.

Page has a lot of methods available to perform actions (most notably, clickName()) and to access it contents (e.g. form(), getElementsByTag()).

The latter are inherited from Tag, which provides access to the Page's DOM. JSoup is used for HTML parsing. Using Tag, you can search for DOM elements in a flexible way. A good example is the implementation of the link part of clickName():

public String clickLinkName(String name, int i) {
    TagList list = getElementsByTag("a").text(name);
    if (i >= list.size())
        return null;
    Tag link = list.get(i);
    String href = link.attr("href");
    return href;
}

FunctionalTest

Let your test classes inherit FunctionalTest. This way, a fakeApplication is started, provisioned with application.conf and stopped automatically.

In your test methods, use the Pages and their public API:

@Test
public void testIndex() {
    IndexPage indexPage = new IndexPage(Page.get("/"));
    indexPage = indexPage.save("Perform Test");
    indexPage = indexPage.clickReload();
}

And remember, Play! 2.3.x Functional Tests give you full access to the database!

funcy's People

Contributors

joergviola avatar megazord avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.