Create Project with Sample Spring Shell Tests

Just like spring-shell/spring-shell-samples shows examples of Spring
Shell features, create a project with samples of Spring Shell unit,
functional and integration tests.

Issue: SHL-192
https://jira.spring.io/browse/SHL-192
This commit is contained in:
Sualeh Fatehi
2018-10-24 19:25:43 -04:00
committed by Eric Bottard
parent 5447db5da7
commit 5ec589909e
13 changed files with 609 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* Main entry point for the illustrative Spring Shell Calculator application.
*
* @author Sualeh Fatehi
*/
@SpringBootApplication
public class CalculatorApplication {
public static void main(final String[] args) {
SpringApplication.run(CalculatorApplication.class, args);
}
}

View File

@@ -0,0 +1,33 @@
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.shell.standard.ShellCommandGroup;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
/**
*
* Basic commands for the illustrative Spring Shell Calculator application.
*
* @author Sualeh Fatehi
*/
@ShellComponent
@ShellCommandGroup("Calculator Commands")
public class CalculatorCommands {
@Autowired
private CalculatorState state;
@ShellMethod(value = "Add two integers")
public int add(final int a, final int b) {
return a + b;
}
@ShellMethod(value = "Add an integer to the value in memory")
public int addToMemory(final int b) {
final int sum = state.getMemory() + b;
state.setMemory(sum);
return sum;
}
}

View File

@@ -0,0 +1,25 @@
package com.example;
/**
*
* Program state for the illustrative Spring Shell Calculator application.
*
* @author Sualeh Fatehi
*/
public class CalculatorState {
private int memory;
public void clear() {
memory = 0;
}
public int getMemory() {
return memory;
}
public void setMemory(final int memory) {
this.memory = memory;
}
}

View File

@@ -0,0 +1,25 @@
package com.example.test;
import static org.springframework.util.ReflectionUtils.invokeMethod;
import javax.validation.constraints.NotNull;
import org.springframework.shell.CommandRegistry;
import org.springframework.shell.MethodTarget;
/**
*
* Utility methods for tests.
*
* @author Sualeh Fatehi
*/
public class BaseCalculatorTest {
protected <T> T invoke(final MethodTarget methodTarget, final Object... args) {
return (T) invokeMethod(methodTarget.getMethod(), methodTarget.getBean(), args);
}
protected MethodTarget lookupCommand(@NotNull final CommandRegistry registry,
@NotNull final String command) {
return registry.listCommands().get(command);
}
}

View File

@@ -0,0 +1,21 @@
package com.example.test;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import com.example.CalculatorState;
/**
*
* Spring configuration with beans for setting up tests.
*
* @author Sualeh Fatehi
*/
@TestConfiguration
public class TestCalculatorStateConfig {
@Bean("state")
public CalculatorState calculatorState() {
return new CalculatorState();
}
}

View File

@@ -0,0 +1,86 @@
package com.example.test.functional;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.util.ReflectionUtils.findMethod;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.shell.ConfigurableCommandRegistry;
import org.springframework.shell.MethodTarget;
import org.springframework.shell.standard.StandardMethodTargetRegistrar;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.example.CalculatorCommands;
import com.example.CalculatorState;
import com.example.test.BaseCalculatorTest;
import com.example.test.TestCalculatorStateConfig;
/**
* Illustrative functional tests for the Spring Shell Calculator application. These
* functional tests use Spring Shell commands auto-wired by the Spring Test Runner outside
* of the shell, to test functionality of the commands.
*
* @author Sualeh Fatehi
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestCalculatorStateConfig.class, CalculatorCommands.class })
public class CalculatorCommandsTest extends BaseCalculatorTest {
private static final Class<CalculatorCommands> COMMAND_CLASS_UNDER_TEST = CalculatorCommands.class;
private final ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
@Autowired
private CalculatorState state;
@Autowired
private ApplicationContext context;
@Before
public void setup() {
final StandardMethodTargetRegistrar registrar = new StandardMethodTargetRegistrar();
registrar.setApplicationContext(context);
registrar.register(registry);
state.clear();
}
@Test
public void testAdd() {
final String command = "add";
final String commandMethod = "add";
final MethodTarget commandTarget = lookupCommand(registry, command);
assertThat(commandTarget, notNullValue());
assertThat(commandTarget.getGroup(), is("Calculator Commands"));
assertThat(commandTarget.getHelp(), is("Add two integers"));
assertThat(commandTarget.getMethod(),
is(findMethod(COMMAND_CLASS_UNDER_TEST, commandMethod, int.class, int.class)));
assertThat(commandTarget.getAvailability().isAvailable(), is(true));
assertThat(invoke(commandTarget, 1, 2), is(3));
assertThat(state.getMemory(), is(0));
}
@Test
public void testaddToMemory() {
final String command = "add-to-memory";
final String commandMethod = "addToMemory";
final MethodTarget commandTarget = lookupCommand(registry, command);
assertThat(commandTarget, notNullValue());
assertThat(commandTarget.getGroup(), is("Calculator Commands"));
assertThat(commandTarget.getHelp(), is("Add an integer to the value in memory"));
assertThat(commandTarget.getMethod(),
is(findMethod(COMMAND_CLASS_UNDER_TEST, commandMethod, int.class)));
assertThat(commandTarget.getAvailability().isAvailable(), is(true));
state.setMemory(1);
assertThat(invoke(commandTarget, 2), is(3));
assertThat(state.getMemory(), is(3));
}
}

View File

@@ -0,0 +1,84 @@
package com.example.test.integration;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.util.ReflectionUtils.findMethod;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.shell.MethodTarget;
import org.springframework.shell.Shell;
import org.springframework.shell.jline.InteractiveShellApplicationRunner;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.example.CalculatorCommands;
import com.example.CalculatorState;
import com.example.test.BaseCalculatorTest;
import com.example.test.TestCalculatorStateConfig;
/**
*
* Illustrative integration tests for the Spring Shell Calculator application. These
* integration tests use Spring Shell auto-wired by the Spring Test Runner.
*
* @author Sualeh Fatehi
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(properties = { InteractiveShellApplicationRunner.SPRING_SHELL_INTERACTIVE_ENABLED + "=" + false })
@ContextConfiguration(classes = TestCalculatorStateConfig.class)
public class CalculatorCommandsIntegrationTest extends BaseCalculatorTest {
private static final Class<CalculatorCommands> COMMAND_CLASS_UNDER_TEST = CalculatorCommands.class;
@Autowired
private Shell shell;
@Autowired
private CalculatorState state;
/**
* Test "happy path" or basic addition with positive numbers and zeroes. Use Spring Shell
* auto-wired by the Spring Test Runner.
*/
@Test
public void testAdd() {
final String command = "add";
final String commandMethod = "add";
final MethodTarget commandTarget = lookupCommand(shell, command);
assertThat(commandTarget, notNullValue());
assertThat(commandTarget.getGroup(), is("Calculator Commands"));
assertThat(commandTarget.getHelp(), is("Add two integers"));
assertThat(commandTarget.getMethod(),
is(findMethod(COMMAND_CLASS_UNDER_TEST, commandMethod, int.class, int.class)));
assertThat(commandTarget.getAvailability().isAvailable(), is(true));
assertThat(shell.evaluate(() -> command + " 1 2"), is(3));
assertThat(state.getMemory(), is(0));
}
/**
* Test "happy path" or basic addition with positive numbers and zeroes, using calculator
* memory (program state). Use Spring Shell and calculator memory auto-wired by the Spring
* Test Runner.
*/
@Test
public void testAddToMemory() {
final String command = "add-to-memory";
final String commandMethod = "addToMemory";
final MethodTarget commandTarget = lookupCommand(shell, command);
assertThat(commandTarget, notNullValue());
assertThat(commandTarget.getGroup(), is("Calculator Commands"));
assertThat(commandTarget.getHelp(), is("Add an integer to the value in memory"));
assertThat(commandTarget.getMethod(),
is(findMethod(COMMAND_CLASS_UNDER_TEST, commandMethod, int.class)));
assertThat(commandTarget.getAvailability().isAvailable(), is(true));
state.setMemory(1);
assertThat(shell.evaluate(() -> command + " 2"), is(3));
assertThat(state.getMemory(), is(3));
}
}

View File

@@ -0,0 +1,50 @@
package com.example.test.unit;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import com.example.CalculatorCommands;
/**
*
* Illustrative unit tests for the Spring Shell Calculator application. The unit tests
* test calculator commands as "plain-old Java objects" or POJOs, without relying on the
* Spring Framework. Boundary conditions of individual methods are tested.
*
* @author Sualeh Fatehi
*/
public class AddTest {
private CalculatorCommands commands;
/**
* Setup test calculator commands as "plain-old Java objects" or POJOs, initialized for
* each test.
*/
@Before
public void setup() {
commands = new CalculatorCommands();
}
/**
* Test "happy path" or basic addition with positive numbers and zeroes.
*/
@Test
public void addHappyPath() {
assertThat(commands.add(0, 1), is(1));
assertThat(commands.add(1, 2), is(3));
assertThat(commands.add(1, 0), is(1));
}
/**
* Test addition with negative numbers and zeroes.
*/
@Test
public void addNegatives() {
assertThat(commands.add(0, -1), is(-1));
assertThat(commands.add(1, -2), is(-1));
assertThat(commands.add(-1, 0), is(-1));
}
}

View File

@@ -0,0 +1,73 @@
package com.example.test.unit;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.springframework.util.ReflectionUtils.findField;
import static org.springframework.util.ReflectionUtils.makeAccessible;
import static org.springframework.util.ReflectionUtils.setField;
import java.lang.reflect.Field;
import org.junit.Before;
import org.junit.Test;
import com.example.CalculatorCommands;
import com.example.CalculatorState;
/**
*
* Illustrative unit tests for the Spring Shell Calculator application. The unit tests
* test calculator commands as "plain-old Java objects" or POJOs, without relying on the
* Spring Framework. Boundary conditions of individual methods are tested.
*
* @author Sualeh Fatehi
*/
public class AddToMemoryTest {
private CalculatorCommands commands;
private CalculatorState state;
/**
* Setup test calculator commands as "plain-old Java objects" or POJOs, initialized for
* each test.
*/
@Before
public void setup() {
state = new CalculatorState();
commands = new CalculatorCommands();
final Field stateField = findField(CalculatorCommands.class, "state");
makeAccessible(stateField);
setField(stateField, commands, state);
}
/**
* Test "happy path" or basic addition with positive numbers and zeroes, using calculator
* memory (program state).
*/
@Test
public void addToMemoryHappyPath() {
assertThat(commands.addToMemory(1), is(1));
assertThat(state.getMemory(), is(1));
assertThat(commands.addToMemory(2), is(3));
assertThat(state.getMemory(), is(3));
assertThat(commands.addToMemory(0), is(3));
assertThat(state.getMemory(), is(3));
}
/**
* Test addition with negative numbers and zeroes, using calculator memory (program
* state).
*/
@Test
public void addToMemoryNegatives() {
assertThat(commands.addToMemory(-1), is(-1));
assertThat(state.getMemory(), is(-1));
assertThat(commands.addToMemory(-2), is(-3));
assertThat(state.getMemory(), is(-3));
assertThat(commands.addToMemory(0), is(-3));
assertThat(state.getMemory(), is(-3));
}
}