Commit 7f226638 authored by Christian Wulf's avatar Christian Wulf

#361: the test framework now prevents to call "test(stage).start()"

parent 0ddf92dc
......@@ -20,7 +20,7 @@ import java.util.Collection;
import teetime.framework.AbstractStage;
import teetime.framework.InputPort;
public final class InputHolder<I> {
public class InputHolder<I> {
private final StageTester stageTester;
private final AbstractStage stage;
......@@ -34,20 +34,20 @@ public final class InputHolder<I> {
this.inputElements = inputElements;
}
public StageTester to(final InputPort<? super I> port) { // NOPMD deliberately chosen name
public StageTestSetup to(final InputPort<? super I> port) { // NOPMD deliberately chosen name
if (port.getOwningStage() != stage) {
throw new IllegalStateException("The given input port does not belong to the stage which should be tested.");
throw new InvalidTestCaseSetupException("The given input port does not belong to the stage which should be tested.");
}
this.port = port;
return stageTester;
return new StageTestSetup(stageTester);
}
public Collection<I> getInputElements() {
/* default */ Collection<I> getInputElements() {
return inputElements;
}
public InputPort<? super I> getPort() {
/* default */ InputPort<? super I> getPort() {
return port;
}
......
package teetime.framework.test;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
abstract class MinimalStageTestSetup {
protected MinimalStageTestSetup() {
// do nothing
}
/**
* @param elements
* which serve as input. If nothing should be sent, pass
*/
@SafeVarargs
public final <I> InputHolder<I> send(final I... elements) {
return this.send(Arrays.asList(elements));
}
/**
* @param elements
* which serve as input. If nothing should be sent, pass
*
* <pre>
* Collections.&lt;your type&gt;emptyList().
* </pre>
*/
public abstract <I> InputHolder<I> send(final Collection<I> elements);
/**
* @param actualElements
* which should be tested against the expected elements.
*/
public abstract <O> OutputHolder<O> receive(final List<O> actualElements);
}
......@@ -19,7 +19,7 @@ import java.util.List;
import teetime.framework.OutputPort;
public final class OutputHolder<O> {
public class OutputHolder<O> {
private final StageTester stageTester;
private final List<Object> outputElements;
......@@ -33,17 +33,17 @@ public final class OutputHolder<O> {
}
@SuppressWarnings("unchecked")
public StageTester from(final OutputPort<O> port) {
public StageTestSetup from(final OutputPort<O> port) {
this.port = (OutputPort<Object>) port;
return stageTester;
return new StageTestSetup(stageTester);
}
public List<Object> getOutputElements() {
/* default */ List<Object> getOutputElements() {
return outputElements;
}
public OutputPort<Object> getPort() {
/* default */ OutputPort<Object> getPort() {
return port;
}
......
package teetime.framework.test;
import java.util.Collection;
import java.util.List;
import teetime.framework.Configuration;
import teetime.framework.Execution;
import teetime.framework.ExecutionException;
public class StageTestSetup extends MinimalStageTestSetup {
private final StageTester stageTester;
/* default */ StageTestSetup(final StageTester stageTester) {
this.stageTester = stageTester;
}
public StageTestSetup and() {
return this;
}
/**
* This method will start the test and block until it is finished.
*
* @return
*
* @throws ExecutionException
* if at least one exception in one thread has occurred within the analysis.
* The exception contains the pairs of thread and throwable.
*
*/
public StageTestResult start() {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Configuration configuration = new TestConfiguration(stageTester.getInputHolders(), stageTester.getStage(), stageTester.getOutputHolders());
final Execution<Configuration> analysis = new Execution<Configuration>(configuration);
analysis.executeBlocking();
StageTestResult result = new StageTestResult();
for (OutputHolder<?> outputHolder : stageTester.getOutputHolders()) {
result.add(outputHolder.getPort(), outputHolder.getOutputElements());
}
return result;
}
@Override
public <I> InputHolder<I> send(final Collection<I> elements) {
return stageTester.send(elements);
}
@Override
public <O> OutputHolder<O> receive(final List<O> actualElements) {
return stageTester.receive(actualElements);
}
}
......@@ -16,20 +16,18 @@
package teetime.framework.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import teetime.framework.*;
import teetime.stage.CollectorSink;
import teetime.stage.InitialElementProducer;
import teetime.framework.AbstractStage;
import teetime.framework.StageState;
/**
* This class can be used to test single stages in JUnit test cases.
*
* @author Nils Christian Ehmke
*/
public final class StageTester {
public class StageTester extends MinimalStageTestSetup {
private final List<InputHolder<?>> inputHolders = new ArrayList<InputHolder<?>>();
private final List<OutputHolder<?>> outputHolders = new ArrayList<OutputHolder<?>>();
......@@ -51,84 +49,44 @@ public final class StageTester {
* which serve as input. If nothing should be sent, pass
*
* <pre>
* Collections.&lt;your type&gt;emptyList()
* Collections.&lt;your type&gt;emptyList().
* </pre>
*
* @return
*/
@SafeVarargs
public final <I> InputHolder<I> send(final I... elements) {
return this.send(Arrays.asList(elements));
}
/**
* @param elements
* which serve as input. If nothing should be sent, pass
*
* <pre>
* Collections.&lt;your type&gt;emptyList()
* </pre>
*
* @return
*/
@Override
public <I> InputHolder<I> send(final Collection<I> elements) {
final InputHolder<I> inputHolder = new InputHolder<I>(this, stage, elements);
this.inputHolders.add(inputHolder);
return inputHolder;
}
public <O> OutputHolder<O> receive(final List<O> outputList) {
final OutputHolder<O> outputHolder = new OutputHolder<O>(this, outputList);
/**
* @param actualElements
* which should be tested against the expected elements.
*/
@Override
public <O> OutputHolder<O> receive(final List<O> actualElements) {
final OutputHolder<O> outputHolder = new OutputHolder<O>(this, actualElements);
this.outputHolders.add(outputHolder);
return outputHolder;
}
/**
* Does nothing. Can be used to make the test more readable.
*/
public StageTester and() {
return this;
}
/**
* This method will start the test and block until it is finished.
*
* @return
*
* @throws ExecutionException
* if at least one exception in one thread has occurred within the analysis.
* The exception contains the pairs of thread and throwable.
*
*/
public StageTestResult start() {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Configuration configuration = new TestConfiguration(inputHolders, stage, outputHolders);
final Execution<Configuration> analysis = new Execution<Configuration>(configuration);
analysis.executeBlocking();
StageTestResult result = new StageTestResult();
for (OutputHolder<?> outputHolder : outputHolders) {
result.add(outputHolder.getPort(), outputHolder.getOutputElements());
}
return result;
/* default */ List<InputHolder<?>> getInputHolders() {
return inputHolders;
}
private static class TestConfiguration<I> extends Configuration {
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
public TestConfiguration(final List<InputHolder<I>> inputHolders, final AbstractStage stage, final List<OutputHolder<?>> outputHolders) {
if (inputHolders.isEmpty() && outputHolders.isEmpty()) {
throw new InvalidTestCaseSetupException("The stage under test must at least receive or send anything.");
}
for (InputHolder<I> inputHolder : inputHolders) {
final InitialElementProducer<I> producer = new InitialElementProducer<I>(inputHolder.getInputElements());
connectPorts(producer.getOutputPort(), inputHolder.getPort());
}
stage.declareActive();
/* default */ List<OutputHolder<?>> getOutputHolders() {
return outputHolders;
}
for (OutputHolder<?> outputHolder : outputHolders) {
final CollectorSink<Object> sink = new CollectorSink<Object>(outputHolder.getOutputElements());
connectPorts(outputHolder.getPort(), sink.getInputPort());
}
}
/* default */ AbstractStage getStage() {
return stage;
}
}
package teetime.framework.test;
import java.util.List;
import teetime.framework.AbstractStage;
import teetime.framework.Configuration;
import teetime.stage.CollectorSink;
import teetime.stage.InitialElementProducer;
class TestConfiguration<I> extends Configuration {
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
public TestConfiguration(final List<InputHolder<I>> inputHolders, final AbstractStage stage, final List<OutputHolder<?>> outputHolders) {
if (inputHolders.isEmpty() && outputHolders.isEmpty()) {
throw new InvalidTestCaseSetupException("The stage under test must at least receive or send anything.");
}
for (InputHolder<I> inputHolder : inputHolders) {
final InitialElementProducer<I> producer = new InitialElementProducer<I>(inputHolder.getInputElements());
connectPorts(producer.getOutputPort(), inputHolder.getPort());
}
stage.declareActive();
for (OutputHolder<?> outputHolder : outputHolders) {
final CollectorSink<Object> sink = new CollectorSink<Object>(outputHolder.getOutputElements());
connectPorts(outputHolder.getPort(), sink.getInputPort());
}
}
}
......@@ -9,6 +9,7 @@ import java.util.List;
import org.junit.Test;
import teetime.stage.Counter;
import teetime.stage.InitialElementProducer;
public class StageTesterTest {
......@@ -30,7 +31,7 @@ public class StageTesterTest {
public void testProducerAlreadyStarted() throws Exception {
InitialElementProducer<Integer> producer = new InitialElementProducer<>(1, 2, 3);
// let the producer be used once before testing it actually
// let the producer be used once before actually testing it
test(producer).receive(new ArrayList<Integer>()).from(producer.getOutputPort()).start();
List<Integer> outputElements = new ArrayList<>();
......@@ -42,21 +43,19 @@ public class StageTesterTest {
assertThat(outputElements, contains(1, 2, 3));
}
@Test(expected = InvalidTestCaseSetupException.class)
public void testProducerWithoutReceive() throws Exception {
InitialElementProducer<Integer> producer = new InitialElementProducer<>(1, 2, 3);
@Test
public void testConsumer() throws Exception {
Counter<Integer> consumer = new Counter<>();
List<Integer> outputElements = new ArrayList<>();
test(producer)
test(consumer).and()
.send(1, 2, 3).to(consumer.getInputPort()).and()
.receive(outputElements).from(consumer.getOutputPort())
.start();
assertThat(outputElements, contains(1, 2, 3));
}
@Test
public void testConsumer() throws Exception {
assertThat(consumer.getNumElementsPassed(), is(3));
}
@Test
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment