added javadoc and other comments

This commit is contained in:
Sander Hautvast 2020-01-22 16:26:25 +01:00
parent 0a4380029e
commit 7888d51f39
14 changed files with 67 additions and 11 deletions

View file

@ -2,6 +2,9 @@ package nl.sander.testautomation.cars;
import java.util.Objects; import java.util.Objects;
/**
* Part of ultra simple Car application
*/
public class Car { public class Car {
private long id; private long id;

View file

@ -3,6 +3,9 @@ package nl.sander.testautomation.cars;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
/**
* Part of ultra simple Car application
*/
public interface CarDao { public interface CarDao {
Car getCar(long carId) throws SQLException; Car getCar(long carId) throws SQLException;

View file

@ -2,6 +2,9 @@ package nl.sander.testautomation.cars;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
/**
* Part of ultra simple Car application
*/
public class CarModule extends AbstractModule { public class CarModule extends AbstractModule {
@Override @Override

View file

@ -4,6 +4,9 @@ import javax.inject.Inject;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Optional; import java.util.Optional;
/**
* Part of ultra simple Car application
*/
public class CarService { public class CarService {
@Inject @Inject

View file

@ -10,6 +10,9 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* Part of ultra simple Car application
*/
public class JdbcCarDao implements CarDao { public class JdbcCarDao implements CarDao {
@Inject @Inject

View file

@ -4,6 +4,9 @@ import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
/**
* Part of ultra simple Car application
*/
public class Database { public class Database {
private final Connection connection; private final Connection connection;

View file

@ -4,6 +4,9 @@ import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions; import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/**
* Example CucumberRunner
*/
@RunWith(Cucumber.class) @RunWith(Cucumber.class)
@CucumberOptions( @CucumberOptions(
strict = true, strict = true,

View file

@ -1,5 +1,8 @@
package nl.sander.testautomation; package nl.sander.testautomation;
/**
* set by the framework driven by cucumber tags. Limited for now
*/
public enum Mode { public enum Mode {
UNIT_TEST, UNIT_TEST,
UNIT_INTEGRATION_TEST, UNIT_INTEGRATION_TEST,

View file

@ -11,16 +11,32 @@ public interface UnitTest {
Injector injector = Guice.createInjector( Injector injector = Guice.createInjector(
override(new CarModule()).with(new UnitTestModule())); override(new CarModule()).with(new UnitTestModule()));
/**
* Unittest must call this to get a real (unmocked) instance that can be tested.
* Any dependencies that can be found in a guice module will be injected.
*
* For now the instance class must have a default constructor.
* @param type the type of the class
* @param <T> generic
* @return an instance of the specified class
*/
default <T> T classToTest(Class<T> type) { default <T> T classToTest(Class<T> type) {
try { try {
T instance = type.newInstance(); T instance = type.newInstance();
injector.injectMembers(instance); injector.injectMembers(instance);
return instance; return instance;
} catch (InstantiationException | IllegalAccessException e) { } catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e); //TODO create descriptive exception
} }
} }
/**
* looks up a mock from the guice module.
*
* @param type The type of the mock
* @param <T> The generic type of the mock
* @return A mocked instance of the given type.
*/
default <T> T mock(Class<T> type) { default <T> T mock(Class<T> type) {
return injector.getInstance(type); return injector.getInstance(type);
} }

View file

@ -8,7 +8,7 @@ import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder; import org.reflections.util.ConfigurationBuilder;
/** /**
* mocks all classes in the SUT * Mocks all classes in the SUT.
* *
* Works but could be optimized by only searching for types/annotations * Works but could be optimized by only searching for types/annotations
*/ */

View file

@ -4,6 +4,9 @@ package nl.sander.testautomation.steps;
import io.cucumber.java.Before; import io.cucumber.java.Before;
import nl.sander.testautomation.Mode; import nl.sander.testautomation.Mode;
/**
* Common stepdefinitions. Used to derive behavior from tags
*/
public class StepDefinitions { public class StepDefinitions {
public static Mode testMode; public static Mode testMode;

View file

@ -22,6 +22,9 @@ import java.util.stream.Collectors;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/**
* Example stepdefinitions for our car application
*/
public class DatabaseStepDefinitions implements En { public class DatabaseStepDefinitions implements En {
private CarDao carDao; private CarDao carDao;
@ -41,13 +44,14 @@ public class DatabaseStepDefinitions implements En {
}); });
Then("^a new car is added to the inventory$", (DataTable dataTable) -> { Then("^a new car is added to the inventory$", (DataTable dataTable) -> {
Map<Long, Car> carRecordsById = this.carDao.getAllCars().stream().collect(Collectors.toMap(Car::getId, Function.identity())); if (StepDefinitions.testMode == Mode.DATABASE_INTEGRATION_TEST) {
dataTable.asMaps().stream() Map<Long, Car> carRecordsById = this.carDao.getAllCars().stream().collect(Collectors.toMap(Car::getId, Function.identity()));
.map(record -> Long.parseLong(record.get("id"))) dataTable.asMaps().stream()
.forEach(carId -> { .map(record -> Long.parseLong(record.get("id")))
assertTrue(String.format("car with id %s not found", carId), carRecordsById.containsKey(carId)); .forEach(carId -> {
}); assertTrue(String.format("car with id %s not found", carId), carRecordsById.containsKey(carId));
});
}
}); });
} }

View file

@ -1,9 +1,9 @@
package nl.sander.testautomation.tests.cars; package nl.sander.testautomation.tests.cars;
import nl.sander.testautomation.UnitTest;
import nl.sander.testautomation.cars.Car; import nl.sander.testautomation.cars.Car;
import nl.sander.testautomation.cars.CarDao; import nl.sander.testautomation.cars.CarDao;
import nl.sander.testautomation.cars.CarService; import nl.sander.testautomation.cars.CarService;
import nl.sander.testautomation.UnitTest;
import org.junit.Test; import org.junit.Test;
import java.sql.SQLException; import java.sql.SQLException;
@ -13,9 +13,16 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
/**
* Example for a pure unit test
*/
public class CarServiceTest implements UnitTest { public class CarServiceTest implements UnitTest {
private final CarDao carDao = mock(CarDao.class); /* lookup mock from guice injector. This is only to set the When for this test */
private final CarDao carDao = mock(CarDao.class); //TODO we might be able to use the @Mock annotation to do the same
/* lookup actual instance. All dependencies with @Inject are automatically injected with mocks */
//TODO we might be able to use the @InjectMocks annotation to do the same
private final CarService carService = classToTest(CarService.class); private final CarService carService = classToTest(CarService.class);
@Test @Test

View file

@ -1,5 +1,7 @@
#Example cucumber test.
Feature: car module Feature: car module
#In this scenario a h2 database is used to test database integration
@DatabaseIntegrationTest @DatabaseIntegrationTest
Scenario: add new car Scenario: add new car
When a user enters a car with id 1: a red volkswagen kever, built in 1967 When a user enters a car with id 1: a red volkswagen kever, built in 1967