Code Monkey home page Code Monkey logo

spectrum's Introduction

Spectrum

Build Status Coverage Status MIT License

A colorful BDD-style test runner for Java

Spectrum is inspired by the behavior-driven testing frameworks Jasmine, Kiwi, and RSpec, bringing their expressive syntax and functional style to Java tests. It is a custom runner for JUnit, so it works with many development and reporting tools out of the box.

Example

from ExampleSpecs.java

@RunWith(Spectrum.class)
public class ExampleSpecs {
  {

    describe("A spec", () -> {

      final int foo = 1;

      it("is just a code block that verifies something", () -> {
        assertEquals(1, foo);
      });

      it("can use any assertion library you like", () -> {
        org.junit.Assert.assertEquals(1, foo);
        org.hamcrest.MatcherAssert.assertThat(true, is(true));
      });

      describe("nested inside a second describe", () -> {

        final int bar = 1;

        it("can reference both scopes as needed", () -> {
          assertThat(bar, is(equalTo(foo)));
        });

      });

      it("can have `it`s and `describe`s in any order", () -> {
        assertThat(foo, is(1));
      });

    });

    describe("A suite using beforeEach and afterEach", () -> {

      final List<String> items = new ArrayList<>();

      beforeEach(() -> {
        items.add("foo");
      });

      beforeEach(() -> {
        items.add("bar");
      });

      afterEach(() -> {
        items.clear();
      });

      it("runs the beforeEach() blocks in order", () -> {
        assertThat(items, contains("foo", "bar"));
        items.add("bogus");
      });

      it("runs them before every spec", () -> {
        assertThat(items, contains("foo", "bar"));
        items.add("bogus");
      });

      it("runs afterEach after every spec", () -> {
        assertThat(items, not(contains("bogus")));
      });

      describe("when nested", () -> {

        beforeEach(() -> {
          items.add("baz");
        });

        it("runs beforeEach and afterEach from inner and outer scopes", () -> {
          assertThat(items, contains("foo", "bar", "baz"));
        });

      });

    });

    describe("The Value convenience wrapper", () -> {

      final Value<Integer> counter = value();

      beforeEach(() -> {
        counter.value = 0;
      });

      beforeEach(() -> {
        counter.value++;
      });

      it("lets you work around Java's requirement that closures only use `final` variables", () -> {
        counter.value++;
        assertThat(counter.value, is(2));
      });

      it("can optionally have an initial value set", () -> {
        final Value<String> name = value("Alice");
        assertThat(name.value, is("Alice"));
      });

      it("has a null value if not specified", () -> {
        final Value<String> name = value();
        assertThat(name.value, is(nullValue()));
      });

    });

    describe("A suite using beforeAll", () -> {

      final List<Integer> numbers = new ArrayList<>();

      beforeAll(() -> {
        numbers.add(1);
      });

      it("sets the initial state before any specs run", () -> {
        assertThat(numbers, contains(1));
        numbers.add(2);
      });

      describe("and afterAll", () -> {

        afterAll(() -> {
          numbers.clear();
        });

        it("does not reset anything between tests", () -> {
          assertThat(numbers, contains(1, 2));
          numbers.add(3);
        });

        it("so proceed with caution; this *will* leak shared state across specs", () -> {
          assertThat(numbers, contains(1, 2, 3));
        });
      });

      it("cleans up after running all specs in the describe block", () -> {
        assertThat(numbers, is(empty()));
      });

    });

  }
}

Focused Specs

You can focus the runner on particular spec with fit or a suite with fdescribe so that only those specs get executed.

from FocusedSpecs.java

describe("Focused specs", () -> {

  fit("is focused and will run", () -> {
    assertThat(true, is(true));
  });

  it("is not focused and will not run", () -> {
    throw new Exception();
  });

  fdescribe("a focused suite", () -> {

    it("will run", () -> {
      assertThat(true, is(true));
    });

    it("all its specs", () -> {
      assertThat(true, is(true));
    });
  });

  fdescribe("another focused suite, with focused and unfocused specs", () -> {

    fit("will run focused specs", () -> {
      assertThat(true, is(true));
    });

    it("ignores unfocused specs", () -> {
      throw new Exception();
    });
  });
});

Ignored Specs

You can ignore a spec with xit or ignore all the specs in a suite with xdescribe.

from IgnoredSpecs.java

describe("Ignored specs", () -> {

    xit("is ignored and will not run", () -> {
        throw new Exception();
    });

    it("is not ignored and will run", () -> {
        assertThat(true, is(true));
    });

    xdescribe("an ignored suite", () -> {

        it("will not run", () -> {
            throw new Exception();
        });

        describe("with nesting", () -> {
            it("all its specs", () -> {
                throw new Exception();
            });

            fit("including focused specs", () -> {
                throw new Exception();
            });
        });
    });
});

Common Variable Initialization

The let helper function makes it easy to initialize common variables that are used in multiple specs. This also helps work around Java's restriction that closures can only reference final variables in the containing scope. Values are cached within a spec, and lazily re-initialized between specs as in RSpec #let.

from LetSpecs.java

describe("The `let` helper function", () -> {

  final Supplier<List<String>> items = let(() -> new ArrayList<>(asList("foo", "bar")));

  it("is a way to supply a value for specs", () -> {
    assertThat(items.get(), contains("foo", "bar"));
  });

  it("caches the value so it doesn't get created multiple times for the same spec", () -> {
    assertThat(items.get(), is(sameInstance(items.get())));

    items.get().add("baz");
    items.get().add("blah");
    assertThat(items.get(), contains("foo", "bar", "baz", "blah"));
  });

  it("creates a fresh value for every spec", () -> {
    assertThat(items.get(), contains("foo", "bar"));
  });
});

Supported Features

Spectrum moving toward a 1.0 release with close alignment to Jasmine's test declaration API. The library already supports a nice subset of those features:

  • describe
  • it
  • beforeEach / afterEach
  • beforeAll / afterAll
  • fit / fdescribe
  • xit / xdescribe

Non-Features

Unlike some BDD-style frameworks, Spectrum is only a test runner. Assertions, expectations, mocks, and matchers are the purview of other libraries.

Getting Started

Spectrum is available as a package on jCenter, so make sure you have jCenter declared as a repository in your build config. Future inclusion in Maven Central (see #12) will make this even easier.

Dependencies

  • JUnit 4
  • Java 8 (for your tests; systems under test can use older versions)

Gradle

Make sure you have the jCenter repository in your init script or project build.gradle:

repositories {
    jcenter()
}

Then add the Spectrum dependency for your tests:

dependencies {
  testCompile 'com.greghaskins:spectrum:0.7.0'
}

Maven

Make sure you have the jCenter repository in your global settings.xml or project pom.xml:

<repositories>
    <repository>
        <id>jcenter</id>
        <url>http://jcenter.bintray.com</url>
    </repository>
</repositories>

Then add Spectrum as a dependency with test scope in your pom.xml:

<project>
  <dependencies>
    <dependency>
      <groupId>com.greghaskins</groupId>
      <artifactId>spectrum</artifactId>
      <version>0.7.0</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Can I Contribute?

Yes please! See CONTRIBUTING.md.

spectrum's People

Contributors

greghaskins avatar

Watchers

 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.