
ar.com.dgarcia.javaspec.impl.DefinitionMode Maven / Gradle / Ivy
package ar.com.dgarcia.javaspec.impl;
import ar.com.dgarcia.javaspec.api.JavaSpecApi;
import ar.com.dgarcia.javaspec.api.contexts.ClassBasedTestContext;
import ar.com.dgarcia.javaspec.api.contexts.TestContext;
import ar.com.dgarcia.javaspec.api.exceptions.FailingRunnable;
import ar.com.dgarcia.javaspec.api.exceptions.SpecException;
import ar.com.dgarcia.javaspec.api.variable.Variable;
import ar.com.dgarcia.javaspec.impl.context.typed.TypedContextFactory;
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.util.function.Consumer;
/**
* This type represents the available api when the tests are being defined.
* Through an instance of this class a spec tree can be populated by calling the
* user available methods to create a complete spec definition
*
* Created by kfgodel on 09/03/16.
*/
public class DefinitionMode implements JavaSpecApi {
private SpecStack stack;
private SpecTree specTree;
private T typedContext;
private RunningMode runningMode;
public void beforeEach(Runnable aCodeBlock) {
stack.getCurrentHead().addBeforeBlock(aCodeBlock);
}
@Override
public void afterEach(Runnable aCodeBlock) {
stack.getCurrentHead().addAfterBlock(aCodeBlock);
}
@Override
public void it(String testName, Runnable aTestCode) {
TestSpecDefinition createdSpec = TestSpecDefinition.create(testName, aTestCode, specTree.getSharedContext());
stack.getCurrentHead().addTest(createdSpec);
}
@Override
public void it(String testName) {
TestSpecDefinition createdSpec = TestSpecDefinition.createPending(testName, specTree.getSharedContext());
stack.getCurrentHead().addTest(createdSpec);
}
@Override
public void xit(String testName, Runnable aTestCode) {
TestSpecDefinition createdSpec = TestSpecDefinition.create(testName, aTestCode, specTree.getSharedContext());
createdSpec.markAsPending();
stack.getCurrentHead().addTest(createdSpec);
}
@Override
public void itThrows(Class expectedExceptionType, String testNameSuffix, FailingRunnable aTestCode, Consumer exceptionAssertions) throws SpecException {
String expectedTypeName = expectedExceptionType.getSimpleName();
String testName = "throws " + expectedTypeName + " " + testNameSuffix;
Runnable testCode = ()->{
try {
aTestCode.run();
throw new AssertionError("Expected an exception of type: " + expectedTypeName + " but none was thrown");
}catch (AssertionError e){
throw e;
}catch (Throwable e){
if(expectedExceptionType.isAssignableFrom(e.getClass())){
exceptionAssertions.accept((X) e);
}else{
throw new AssertionError("Expection an exception of type: " + expectedTypeName + " but caught a different: " + e, e);
}
}
};
it(testName, testCode);
}
@Override
public void describe(String aGroupName, Runnable aGroupDefinition) {
createGroupDefinition(aGroupName, aGroupDefinition);
}
@Override
public void xdescribe(String aGroupName, Runnable aGroupDefinition) {
GroupSpecDefinition createdGroup = createGroupDefinition(aGroupName, aGroupDefinition);
createdGroup.markAsDisabled();
}
@Override
public void describe(Class> aClass, Runnable aGroupDefinition){
createClassBasedGroupDescription(aClass, aGroupDefinition);
}
@Override
public void xdescribe(Class> aClass, Runnable aGroupDefinition) {
GroupSpecDefinition groupDefinition = createClassBasedGroupDescription(aClass, aGroupDefinition);
groupDefinition.markAsDisabled();
}
/**
* Creates the description of a class based test group
* @param aClass The class to base the group on
* @param aGroupDefinition The test definitions
* @return The created group
*/
private GroupSpecDefinition createClassBasedGroupDescription(Class> aClass, Runnable aGroupDefinition) {
// Sanity check to verify correct usage
if(!ClassBasedTestContext.class.isInstance(context())){
throw new SpecException("#describe can't be called with a class if the test context is not a ClassBasedTestContext subtype");
}
// Junit likes to split the description if I use the full class name
String groupName = "class: " + aClass.getSimpleName();
GroupSpecDefinition groupDefinition = createGroupDefinition(groupName, aGroupDefinition);
ClassBasedTestContext classContext = (ClassBasedTestContext) groupDefinition.getTestContext();
classContext.describedClass(()-> aClass);
return groupDefinition;
}
private GroupSpecDefinition createGroupDefinition(String aGroupName, Runnable aGroupDefinition) {
GroupSpecDefinition createdGroup = GroupSpecDefinition.create(aGroupName);
stack.executeAsCurrent(createdGroup, aGroupDefinition);
stack.getCurrentHead().addSubGroup(createdGroup);
return createdGroup;
}
/**
* Allows access to test context, to define variables or to access them.
* Usually you define variables in suites and access them in tests
*
* @return The current test context
*/
public T context() {
return typedContext;
}
@Override
public void given(Runnable setupCode) {
context().setupCode(()-> setupCode);
}
@Override
public void when(Runnable exerciseCode) {
context().exerciseCode(()-> exerciseCode);
}
@Override
public void then(Runnable assertionCode) {
context().assertionCode(()-> assertionCode);
}
@Override
public void itThen(String testName, Runnable assertionCode) {
it(testName, ()->{
// We call then() method, but the running test version
runningMode.then(assertionCode);
});
}
@Override
public void executeAsGivenWhenThenTest() {
throw new SpecException("Execution can't be done outside a test. it must be called inside an it() lambda");
}
/**
* Creates a new spec describer that will populate the branches of the given tree when its methods
* are called
* @param specTree The tree to collect the spec meta description
* @param The type of test context
* @return The created describer
*/
public static DefinitionMode create(SpecTree specTree, Class expectedContextType) {
DefinitionMode describer = new DefinitionMode<>();
describer.specTree = specTree;
describer.initialize(expectedContextType);
return describer;
}
/**
* Initializes this instance with the stack and context to collect spec meta description
* from the method calls
* @param expectedContextType
*/
private void initialize(Class expectedContextType) {
SpecGroup rootGroup = this.specTree.getRootGroup();
Variable sharedContext = this.specTree.getSharedContext();
this.stack = SpecStack.create(rootGroup, sharedContext);
this.typedContext = TypedContextFactory.createInstanceOf(expectedContextType, sharedContext);
this.runningMode = RunningMode.create(this.context());
}
/**
* Creates a running mode based on the current definitions for this instance
* @return The running version of this mode
*/
public RunningMode changeToRunning() {
return runningMode;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy