Package ar.com.dgarcia.javaspec.api

Source Code of ar.com.dgarcia.javaspec.api.JavaSpec

package ar.com.dgarcia.javaspec.api;

import ar.com.dgarcia.javaspec.impl.context.typed.TypedContextFactory;
import ar.com.dgarcia.javaspec.impl.exceptions.SpecException;
import ar.com.dgarcia.javaspec.impl.model.SpecGroup;
import ar.com.dgarcia.javaspec.impl.model.SpecTree;
import ar.com.dgarcia.javaspec.impl.model.impl.GroupSpecDefinition;
import ar.com.dgarcia.javaspec.impl.model.impl.TestSpecDefinition;
import ar.com.dgarcia.javaspec.impl.parser.SpecStack;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
* This class is the extension point to add testing expressiveness with Java Specs.<br>
*     The method idiom is copied from: http://jasmine.github.io/2.0/introduction.html.<br>
* Created by kfgodel on 12/07/14.
*/
public abstract class  JavaSpec<T extends TestContext> {

    private SpecTree specTree;
    private SpecStack stack;
    private T typedContext;

    /**
     * Starting method to define the specs.<br>
     *     This method must be extended by subclasses and define any spec as calls to describe() and it()
     */
    public abstract void define();

    /**
     * Code to execute before every it() test. It's scoped to the parent describe() or define(), and executed before every child it() test (direct or nested).<br>
     * @param aCodeBlock A code to execute before every test
     */
    public void beforeEach(Runnable aCodeBlock) {
        stack.getCurrentHead().addBeforeBlock(aCodeBlock);
    }

    /**
     * Code to execute after every it() test. It's scoped to the parent describe() or define(), and executed after every child it() test (direct or nested).<br>
     * @param aCodeBlock
     */
    public void afterEach(Runnable aCodeBlock) {
        stack.getCurrentHead().addAfterBlock(aCodeBlock);
    }

    /**
     * Defines the test code to be run as a test.<br> Every parent beforeEach() is executed prior to this test. Every parent afterEach() is executed after.
     * @param testName The name to identify this test
     * @param aTestCode The code that defines the test
     */
    public void it(String testName, Runnable aTestCode){
        TestSpecDefinition createdSpec = TestSpecDefinition.create(testName, aTestCode, specTree.getSharedContext());
        stack.getCurrentHead().addTest(createdSpec);
    }

    /**
     * Declares a pending test that will be listed as ignored
     * @param testName The name to identify this test
     */
    public void it(String testName){
        TestSpecDefinition createdSpec = TestSpecDefinition.createPending(testName, specTree.getSharedContext());
        stack.getCurrentHead().addTest(createdSpec);
    }

    /**
     * Declares an ignored test. It will not be run, but listed
     * @param testName The name to identify this test
     * @param aTestCode The ignored code of this tests
     */
    public void xit(String testName, Runnable aTestCode){
        TestSpecDefinition createdSpec = TestSpecDefinition.create(testName, aTestCode, specTree.getSharedContext());
        createdSpec.markAsPending();
        stack.getCurrentHead().addTest(createdSpec);
    }

    /**
     * Describes a set of test, and allows nesting of scenarios
     * @param aGroupName The name of the test group
     * @param aGroupDefinition The code that defines sub-tests, or sub-contexts
     */
    public void describe(String aGroupName, Runnable aGroupDefinition){
        createGroupDefinition(aGroupName, aGroupDefinition);
    }

    private GroupSpecDefinition createGroupDefinition(String aGroupName, Runnable aGroupDefinition) {
        GroupSpecDefinition createdGroup = GroupSpecDefinition.create(aGroupName);
        stack.executeAsCurrent(createdGroup, aGroupDefinition);
        stack.getCurrentHead().addSubGroup(createdGroup);
        return createdGroup;
    }

    /**
     * Declares a disabled suite of tests. Any sub-test or sub-context will be ignored (listed but not run)
     * @param aGroupName The name identifying the group
     * @param aGroupDefinition The code that defines sub-tests, or sub-contexts
     */
    public void xdescribe(String aGroupName, Runnable aGroupDefinition){
        GroupSpecDefinition createdGroup = createGroupDefinition(aGroupName, aGroupDefinition);
        createdGroup.markAsDisabled();
    }


    /**
     * Uses the definition of this spec class to create the nodes in the tree.<br>
     *     The defined tree must be validated before using it
     * @param specTree The tree that will represent this spec
     */
    public void populate(SpecTree specTree) {
        this.specTree = specTree;
        SpecGroup rootGroup = this.specTree.getRootGroup();
        Variable<TestContext> sharedContext = this.specTree.getSharedContext();
        this.stack = SpecStack.create(rootGroup, sharedContext);
        Class<T> expectedContextType = this.getContextTypeFromSubclassDeclaration();
        this.typedContext = TypedContextFactory.createInstanceOf(expectedContextType, sharedContext);
        this.define();
    }

    /**
     * Allows access to test context, to define variables or to access them.<br>
     *  Usually you define variables in suites and access them in tests
     * @return The current test context
     */
    protected T context() {
        return typedContext;
    }

    public Class<T> getContextTypeFromSubclassDeclaration() {
        Class<? extends JavaSpec> subClass = getClass();
        if(!(subClass.getSuperclass().equals(JavaSpec.class))){
            throw new SpecException("A java spec class["+ subClass+ "] must inherit directly from " +JavaSpec.class);
        }
        Type generifiedJavaSpec = subClass.getGenericSuperclass();
        if(!(generifiedJavaSpec instanceof ParameterizedType)){
            throw new SpecException("JavaSpec superclass must be generified with a type of TestContext. For example JavaSpec<TestContext>");
        }
        Type contextType = ((ParameterizedType) generifiedJavaSpec).getActualTypeArguments()[0];
        if(!(contextType instanceof Class)){
            throw new SpecException("JavaSpec parameter is not a class?");
        }
        return (Class<T>) contextType;
    }
}
TOP

Related Classes of ar.com.dgarcia.javaspec.api.JavaSpec

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.