Liebling, ich habe die Testpyramide auf den Kopf gestellt






JUG Karlsruhe


Tobse Fritz
- Reich
- Gut aussehend
- ITscope GmbH
- Kotlin Fanboy
- Java Entwickler
- Clean Coder
- Hobby Fotograf
- Gaming Nerd
- 3D Printer
- Daddy










JUG Karlsruhe


JUG Karlsruhe


Lesson
Learned
HOW
TO
Technik
Check
DOS
DONT'S
&
Warum Testen?
Die Test-Pyramide













SpringBoot

MariaDB

ElasticSearch

Redis
Such-Service
Image-Service
Tracking-Service
Price-Service
Vue.js
RedGiant
Technik
Check

FRONTEND
BACKEND

FRONTEND
BACKEND
TESTS


SOFTWARE QUALITÄT
https://de.wikipedia.org/wiki/ISO/IEC_9126
Was nicht getestet ist,
geht kaputt
velocity-tempaltes
messages
model
Contract
getActualEndDateLegacy: Date
getActualEndDateLegacy: Date
Was nicht getestet ist,
geht kaputt
velocity-tempaltes
messages
model
Contract
getActualEndDate: Date
Was nicht getestet ist,
geht kaputt
velocity-tempaltes
messages
model
Contract
getActualEndDate: Date
<ul>
#foreach ( $contract in $subs )
<li>
#set($aDate = $dateTool.getDate())
#if ($contract.getActualEndDate())
#set($aDate = $contract.getActualEndDateLegacy())
#end
$contractMessages.message("notify_change_plan_ends", $dateUtils.format($aDate))
</li>
#end
</ul>
notify_change.vm

User
Tested


User
Tested




User
Tested





User
Tested





User
Tested
Was nicht getestet ist,
wird missachtet





Was nicht getestet ist,
wird missachtet
@Test
public void allKeysAreTranslatedInEnglish() {
List<MessageKey> missingEn = newArrayList();
for (MessageKey key : translationLoader.getTranslation()) {
if (key.getValues().get(Locale.GERMAN).hasTranslation() &&
!key.getValues().get(Locale.ENGLISH).hasTranslation()) {
missingEn.add(key);
}
}
String message = "These keys have no English translation in " + listKeys(missingEn);
message += "\n Please provide an English translation";
assertThat(message, missingEn, hasSize(0));
}
java.lang.AssertionError: These keys have no English translation in messages_en.properties:
Account_Api_CollapseAll
Please provide an English translation
Expected: a collection with size <0>
but: collection size was <1>
Was nicht getestet ist,
wird missachtet
Tests für schnelles
Feedback
Automatisiert
Tests zum Lernen
/ Ausprobieren

Tests?
Tests!
Tests!
Tests!
1 Bug
1 Neuer Test
1 Feature
1 Neuer Test
Lesson
Learned
Unit
Service
UI
Automatisiert
langsam
schnell
mehr Integration
mehr Isolation
Die Testpyramide
Unit
Service
UI
Automatisiert
API Tests
Integrations Tests
Component Tests
Die Testpyramide
Unit
Service
UI
Automatisiert
Die Testpyramide
Service wird hochgefahren
Test von Service-Funktionen, bei dem andere Services gemockt sind
User Ähnlichen Case, der durch
mehrere Codestellen
(Klassen, Funktionen) durchführt
Funktionalität einer Service-Methode im Zusammenspiel mit allen anderen Komponenten sicherstellen
Unit
Service
UI


Automatisiert
Die Testpyramide
Unit
Service
UI
Manuelle Tests
Die Testpyramide
Das Testprotokoll
Lesson
Learned

Unit
Service
UI
Manuelle Tests
AUTOMATED
Die Ampel im Büro

4 Fehlgeschlagene Tests

Lesson
Learned
Test Step blockiert merge


Lesson
Learned
Test Step blockiert merge


Lesson
Learned
Frühjahrsputz - für jeden Commit
> Task :price-stock-service:ktlintMainSourceSetCheck FAILED
C:\Users\..\ServerJob.kt:15 Unused import
C:\Users\..\ServerJob.kt:73 Unexpected indentation (18) (should be 16)
C:\Users\..\ServerJob.kt:74 Unexpected indentation (17) (should be 16)
C:\Users\..\ServerJob.kt:74 Exceeded max line length (160) (cannot be auto-corrected)

> gradle ktlint

AUTOMATED
HACK THE
PEOPLE
Tests als Dokumentation
private final MoneyParser parserDE = new DefaultMoneyParser();
@Test
public void parseCurrencyDE() throws Exception {
assertThat(parserDE.parseCurrency("20,11"), is(new Money("20.11")));
assertThat(parserDE.parseCurrency("42100,00"), is(new Money("42100.00")));
assertThat(parserDE.parseCurrency("42100"), is(new Money("42100")));
assertThat(parserDE.parseCurrency("42.100"), is(new Money("42100")));
assertThat(parserDE.parseCurrency("42.100,00"), is(new Money("42100.00")));
assertThat(parserDE.parseCurrency("42.100,11"), is(new Money("42100.11")));
assertThat(parserDE.parseCurrency("-42.100,11"), is(new Money("-42100.11")));
}

TO
HOW
Tests als Dokumentation
@Test
public void parseCurrencyDE() throws Exception {
// Preapre
MoneyParser parserDE = new DefaultMoneyParser();
// Execute
Money parsed = parserDE.parseCurrency("20,11");
// Verify
assertThat(parsed, is(new Money("20.11")));
}
Prepare
Execute
Verify
Given
When
Then
TO
HOW
Tests als Dokumentation
@Test
@DisplayName("Parse German currency")
public void parseCurrencyDE() throws Exception {
// Prepare
MoneyParser parserDE = new DefaultMoneyParser();
// Execute
Money parsed = parserDE.parseCurrency("20,11");
// Verify
assertThat(parsed, is(new Money("20.11")));
}


TO
HOW
Tests als Dokumentation
@Test
@DisplayName("Parse German currency")
public void parseCurrencyDE() throws Exception {
// Prepare
MoneyParser parserDE = new DefaultMoneyParser();
// Execute
Money parsed = parserDE.parseCurrency("20,11");
// Verify
assertThat(parsed, is(new Money("20.11")));
}
- Passes the tests
- Reveals intention
- No duplication
- Fewest elements
Kent Beck
Extreme Programming
Test Driven Development

TO
HOW
Tests als Dokumentation
- Passes the tests
- Reveals intention
- No duplication
- Fewest elements

TO
HOW
Tests als Dokumentation
- Passes the tests
- Reveals intention
- No duplication
- Fewest elements
@Test
public void someTest() {
StringBuilder sb = new StringBuilder();
sb.append("test");
sb.append((char) 65);
sb.append((char) 10);
sb.append((char) 13);
sb.append((char) 127);
for (int i = 0; i < 31; i++) {
sb.append((char) i);
}
assertTrue(MessageUtil.foo(sb.toString()).indexOf(10) > -1);
assertTrue(MessageUtil.foo(sb.toString()).indexOf(13) > -1);
assertEquals(MessageUtil.foo(sb.toString()).indexOf(3), -1);
assertEquals(MessageUtil.foo(sb.toString()).indexOf(15), -1);
assertEquals(MessageUtil.foo(sb.toString()).indexOf(28), -1);
}
TO
HOW
Tests als Dokumentation
- Passes the tests
- Reveals intention
- No duplication
- Fewest elements
@Test
public void removeCtrlChars_parameterTest() {
StringBuilder sb = new StringBuilder();
sb.append("test");
sb.append((char) 65);
sb.append((char) 10);
sb.append((char) 13);
sb.append((char) 127);
for (int i = 0; i < 31; i++) {
sb.append((char) i);
}
assertTrue(MessageUtil.removeCtrlChars(sb.toString()).indexOf(10) > -1);
assertTrue(MessageUtil.removeCtrlChars(sb.toString()).indexOf(13) > -1);
assertEquals(MessageUtil.removeCtrlChars(sb.toString()).indexOf(3), -1);
assertEquals(MessageUtil.removeCtrlChars(sb.toString()).indexOf(15), -1);
assertEquals(MessageUtil.removeCtrlChars(sb.toString()).indexOf(28), -1);
}
TO
HOW
Tests als Dokumentation
- Passes the tests
- Reveals intention
- No duplication
- Fewest elements
@Test
public void removeCtrlCharsKeepsNewLine() {
String newLine = String.valueOf((char) 10); // new line (/n)
String cleaned = MessageUtil.removeCtrlChars(newLine);
assertTrue(MessageUtil.removeCtrlChars(newLine).contains(newLine));
}
@Test
public void removeCtrlCharsRemovesShiftIn() {
String shiftIn = String.valueOf((char) 15); // Shift In control (unicode: \u000F)
String cleaned = MessageUtil.removeCtrlChars(shiftIn);
assertFalse(cleaned.contains(shiftIn));
}
TO
HOW
Aussagekräftige Fehler
@Test
public void removeCtrlCharsRemovesShiftIn() {
String shiftIn = String.valueOf((char) 15); // Shift In control (unicode: \u000F)
String cleaned = MessageUtil.removeCtrlChars(shiftIn);
assertFalse(cleaned.contains(shiftIn));
}
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:87)
at org.junit.Assert.assertFalse(Assert.java:65)
at de.itscope.mv.service.plcrawler.MessageUtilTest.
removeCtrlCharsRemovesShiftIn(MessageUtilTest.java:39)
Lesson
Learned
Aussagekräftige Fehler
@Test
public void removeCtrlCharsRemovesShiftIn() {
String shiftIn = String.valueOf((char) 15); // Shift In control (unicode: \u000F)
String cleaned = MessageUtil.removeCtrlChars(shiftIn);
assertThat(cleaned, is(emptyString()));
}
java.lang.AssertionError:
Expected: is an empty string
but: was ""
Hamcrest
Lesson
Learned
Aussagekräftige Fehler
@Test
public void removeCtrlCharsRemovesShiftIn() {
String shiftIn = String.valueOf((char) 15); // Shift In control (unicode: \u000F)
String cleaned = MessageUtil.removeCtrlChars(shiftIn);
assertThat("Shift control symbol should be removed",
cleaned, is(emptyString()));
}
java.lang.AssertionError: Shift control symbol should be removed
Expected: is an empty string
but: was ""
Hamcrest
Lesson
Learned
Randfälle Testen

Ein Software-Tester
läuft in eine Bar und
Jasmine Harpley - ministryoftesting.com
schlendert in die Bar...
gallopiert in die Bar...
rennt in die Bar...
spaziert in die Bar...
TO
HOW
Randfälle Testen
Jokin Aspiazu - ministryoftesting.com

Ein Tester
läuft in eine
Bar und
bestellt
-1 Bier.
TO
HOW
Randfälle Testen
@Test
public void parseEmpty() {
MoneyParser parserDE = new DefaultMoneyParser();
assertThrows(ParseException.class, () -> parserDE.parseCurrency(""));
}


@Test
public void parseNull() {
MoneyParser parserDE = new DefaultMoneyParser();
assertThrows(ParseException.class, () -> parserDE.parseCurrency(null));
}
@Test
public void parseNull() {
MoneyParser parserDE = new DefaultMoneyParser();
assertThat(parserDE.parseCurrency("4.20"), is(new Money("420")));
}
TO
HOW
Unit-Tests - klein und schnell

public class MoneyParserTest
Die 100 schnellsten aus 128 in Modul
max: 0,8 s
∅ 60 ms
Mocks
Lesson
Learned
or no Mocks

Mocks
Lesson
Learned
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
Mocks
Lesson
Learned
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
Mocks
Lesson
Learned
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
Mocks
Lesson
Learned
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
val status: OrderStatus = placeOrder(product)
if (status == OrderStatus.OK) {
emailService.sendMail("You ordered $product")
}
return status
}
private fun placeOrder(product: Product): OrderStatus {
return OrderStatus.OK
}
}
Mocks
Lesson
Learned
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
Mocks
Lesson
Learned
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
@Test
fun testOrderService() {
val orderService = OrderService(emailService = ???)
val status = orderService.order(Product("IPad"))
assertEquals(status, OrderStatus.OK)
}
Mocks
or no Mocks
@Test
fun testOrderService() {
val orderService = OrderService(emailService = object : IEmailService {
override fun sendMail(message: String) {
// ignore
}
})
val status = orderService.order(Product("IPad"))
assertEquals(status, OrderStatus.OK)
}
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
Lesson
Learned
Mocks
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
@Test
fun testOrderService() {
val orderService = OrderService(emailService = Mockito.mock(IEmailService::class.java))
val status = orderService.order(Product("IPad"))
assertEquals(status, OrderStatus.OK)
}

Lesson
Learned
Mocks
or no Mocks
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
class Product(val name: String)
interface IOrderService {
fun order(product: Product): OrderStatus
}
interface IEmailService {
fun sendMail(message: String)
}
enum class OrderStatus { OK, ERROR }
class OrderService(private val emailService: IEmailService) : IOrderService {
override fun order(product: Product): OrderStatus {
//...
}
}
@Test
fun testOrderService() {
val orderService = OrderService(emailService = mockk<IEmailService>()))
val status = orderService.order(Product("IPad"))
assertEquals(status, OrderStatus.OK)
}
Lesson
Learned
Mocks
mockStatic(SessionUtils.class);
mockStatic(JMX.class);
mockStatic(UI.class);
mockStatic(RequestContexts.class);
mockStatic(Activator.class);
mockStatic(RedgiantPlugin.class);
mockStatic(MetricFactory.class);
mockStatic(RedgiantModelActivator.class);
RedgiantModelActivator mockActivator = mock(RedgiantModelActivator.class);
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
Environment mockEnvironment = mock(Environment.class);
FrameworkRegistry mockFrameworkRegistry = mock(FrameworkRegistry.class);
DOrderProposalDContainer mockProposalItems = mock(DOrderProposalDContainer.class);
IPartnershipAccountCache mockAccountCache = mock(IPartnershipAccountCache.class);
DCompanySettingsItem mockCompanySettingsItem = mock(DCompanySettingsItem.class);
AbstractProperty mockProperty = mock(AbstractProperty.class);
PushConfiguration mockPushConfiguration = mock(PushConfiguration.class);
AbstractProperty mockTriggerProperty = mock(AbstractProperty.class);
IRequestContext mockRequestContext = mock(IRequestContext.class);
Page mockPage = mock(Page.class);
WebBrowser mockWebBrowser = mock(WebBrowser.class);
Customer mockCustomer = mock(Customer.class);
when(mockCustomer.isShopCustomer()).thenReturn(false);
IAccountCacheService mockAccountCacheService = Mockito.mock(IAccountCacheService.class);
RedgiantPlugin mockRedgiantPlugin = mock(RedgiantPlugin.class);
UserProfile mockProfile = new UserProfile(mock(User.class), mockCustomer);

MOCKS
EVERYWHERE MOCKS
CartOptimizationManagerTest
Lesson
Learned
Mocks von Pojos
@Test
fun mockPojoTest() {
val product = mock(JProduct::class.java)
`when`(product.name).thenReturn("mocked")
assertEquals(product.name, "mocked")
}
Lesson
Learned
Mocks von Pojos
@Test
fun mockPojoTest() {
val product = mock(JProduct::class.java)
`when`(product.name).thenReturn("mocked")
assertEquals(product.name, "mocked")
product.name = "new"
assertEquals(product.name, "new")
}

Lesson
Learned
Mocks static mit PowerMock


fun isWeekday(): Boolean {
return when(LocalDateTime.now().dayOfWeek){
DayOfWeek.SUNDAY,DayOfWeek.SATURDAY -> false
else -> true
}
}
Lesson
Learned
Mocks static mit PowerMock


@RunWith(PowerMockRunner.class)
@PrepareForTest(LocalDateTime.class)
public class MockTimeTest {
@Test
public void testLocalDateTime() {
mockStatic(LocalDateTime.class);
LocalDateTime now = LocalDateTime.of(2023, 2, 8, 19, 0);
when(LocalDateTime.now()).thenReturn(now);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now")).toReturn(now);
LocalDateTime received = LocalDateTime.now();
assertEquals(now, received);
}
Cannot mock/spy class java.time.LocalDateTime Mockito cannot mock/spy because : - final class
Lesson
Learned

@Test
public void testLocalDateTime(){
try (MockedStatic<?> mocked = mockStatic(LocalDateTime.class)) {
LocalDateTime now = LocalDateTime.of(2023, 2, 8, 19, 0);
mocked.when(LocalDateTime::now).thenReturn(now);
LocalDateTime received = LocalDateTime.now();
assertEquals(now, received);
}
}
Mocks static mit mockito
A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffaf734ac26, pid=32216, tid=22264
Lesson
Learned
fun isWeekdayDefault(now: LocalDateTime = LocalDateTime.now()): Boolean {
return when(now.dayOfWeek){
DayOfWeek.SUNDAY,DayOfWeek.SATURDAY -> true
else -> false
}
}
Testen ohne Mocks
Lesson
Learned
Testen mit Reflections
Tip
private long getNumberOfNonStaticFieldsInClass(Class<?> clazz) {
return Arrays.stream(clazz.getDeclaredFields())
.filter(e -> !e.getName().equals("serialVersionUID"))
.filter(e -> !Modifier.isStatic(e.getModifiers()))
.count();
}
@Override
public MarginRule copyEntity() {
MarginRule marginRule = new MarginRule();
marginRule.setSuppliers(suppliers);
marginRule.setProductTypes(productTypes);
marginRule.setManufacturers(manufacturers);
marginRule.setSurcharge(surcharge);
marginRule.setComment(comment);
return marginRule;
}
public void fieldsCheckFor_MarginRule() {
Class<MarginRule> clazz = MarginRule.class;
long numberOfFieldsInClass = getNumberOfNonStaticFieldsInClass(clazz);
assertThat("You added/removed fields in this tracked entity!" +
"Did you take care of #copyEntity()?"
"If so, adjust 'is' value here ->", numberOfFieldsInClass, is(5));
}
Logging in Tests
JA
NEIN
Lesson
Learned
Logging in Tests
H2
Lesson
Learned
Logging in Tests
@Before
public void setUp() {
TestLogUtil.disableLogForClass(AbstractJacksonWriter.class);
}
public static Log disableLogForClass(Class<?> classWithLogger) {
Log logMock = PowerMockito.mock(Log.class);
Whitebox.setInternalState(classWithLogger, logMock);
return logMock;
}
Log logMock = PowerMockito.mock(Log.class);
Whitebox.setInternalState(classWithLogger, logMock);
return logMock;
}
Lesson
Learned
Logging in Tests
public void testCompanyService(){
Log log = getLog(ThreadUtils.class);
CompanyService companyService = new CompanyService();
Company testCompany = new Company("test");
companyService.saveCompany(testCompany);
Company loaded = companyService.loadCompanyName("test");
log.debug("Loaded Company: " + loaded);
assertEquals(testCompany, loaded);
}
Lesson
Learned
Logging in Tests
public void testCompanyService(){
Log log = getLog(ThreadUtils.class);
CompanyService companyService = new CompanyService();
Company testCompany = new Company("test");
companyService.saveCompany(testCompany);
Company loaded = companyService.loadCompanyName("test");
if(log.isDebugEnabled()){
log.debug("Loaded Company: " + loaded);
}
assertEquals(testCompany, loaded);
}
Lesson
Learned
Approval-Tests

@Test
public void testResetPasswordDE() {
EmailDef emailDef = new EmailDefMock(EmailTemplate.Password.reset);
ResetPasswordDTO dto = new ResetPasswordDTO("Sehr geehrter Herr Müller",
"mueller@mycomapany.de",
resetPasswordLink);
EmailConfiguration emailConfig = new EmailConfigurationMock(dto, Locale.GERMANY);
EmailConfiguration email = emailDef.createEmail(emailConfig);
String mail = email.getBody();
Approvals.verifyHtml(mail);
}

Lesson
Learned
Approval-Tests



Lesson
Learned
Architektur-Tests
mit ArchUnit
RedgiantLinkFactory
RedgiantPlugin
CompanyService
OrderService
Tool-Tip
Architektur-Tests
mit ArchUnit
Tool-Tip
@Test
public void tesRedgiantLinkFactoryNotUsesRedgiantPlugin() {
JavaClasses redgiantLinkFactory = new ClassFileImporter()
.importClasses(RedgiantLinkFactory.class);
ArchRule rule = ArchRuleDefinition
.theClass(RedgiantLinkFactory.class)
.should()
.onlyDependOnClassesThat()
.areNotAssignableTo(RedgiantPlugin.class)
.because("It's not allowed to use Services with the deprecated RedgiantPlugin." +
" Instead provide them as parameter.");
rule.check(redgiantLinkFactory);
}

RedgiantLinkFactory
RedgiantPlugin
Architektur-Tests
mit ArchUnit

new Label(getContactInformationHtml(contactDetails), ContentMode.HTML);
Tool-Tip
Architektur-Tests
mit ArchUnit
new Label(getContactInformationHtml(contactDetails), ContentMode.HTML);
new HtmlLabel(getContactInformationHtml(contactDetails), SanitizeMode.NORMAL);

Tool-Tip
Service Tests
Unit
Service
UI
You are Here
Unit
Service
UI
You are Here
Service Tests
Service Tests
RedGiant
Unit-Tests
Integrations-Tests
Selenium-Tests
Technik
Check
Service Tests
RedGiant
Unit-Tests
Integrations-Tests
Selenium-Tests
MariaDB

ElasticSearch

Redis
Such-Service
Image-Service
Tracking-Service
integration-test
Technik
Check
Service Tests
RedGiant
Unit-Tests
Integrations-Tests
Selenium-Tests
MariaDB

ElasticSearch

Redis
Such-Service
Image-Service
Tracking-Service
integration-test
AbstractIntegrationTest
createTestEnvironment() initCompany() initSession()
Technik
Check
Service Tests
Unit-Tests
Integrations-Tests
Selenium-Tests
integration-test
AbstractIntegrationTest
createTestEnvironment() initCompany() initSession()
AllTestsSuite
SofortPaymentTest
EmailPollerTest
erbt
erbt
führt aus
JUnit
Technik
Check
Service Tests
Integration-Test-UI

x

Technik
Check
Service Tests
PRO
CONS
- Schnelle Tests
- Verhalten (fast) wie live
- Testsetup für
für neue Test klein
- Serverstart nötig
- Lokale Ausführung
nur über Web-UI - Kein Test-Scope, da alle Services mitstarten
- Test Isolation aufwendig
Lesson
Learned
CompanyRepository
CompanyService
CompanyServiceAPI
Integartion-Test
Company

CompanyService
UserService
CartService
UserService
UserService
TO
HOW
Maria
DB
Spring-Boot Test

Service Tests mit
CompanyRepository
CompanyService
CompanyServiceAPI
Integartion-Test
Company

CompanyService
UserService
CartService
UserService
UserService
TO
HOW
Maria
DB
Spring-Boot Test

Service Tests mit
CompanyRepository
CompanyService
CompanyServiceAPI
Integartion-Test
Company

CompanyService
TO
HOW
Maria
DB
H2
Spring-Boot Test

Service Tests mit
CompanyRepository
CompanyService
CompanyServiceAPI
Integartion-Test
Company

CompanyService
TO
HOW
H2
Spring-Boot Test

Service Tests mit
TO
HOW
Spring-Boot Test

Service Tests mit
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { StudentJpaConfig.class },
loader = AnnotationConfigContextLoader.class),
@PropertySource("h2-datasource.properties")
@Transactional
public class InMemorySampleDBTest {
@Resource
private StudentRepository studentRepository;
@Test
public void givenStudent_whenSave_thenGetOk() {
Student student = new Student(1, "john");
studentRepository.save(student);
Optional<Student> result = studentRepository.findById(1L);
Student found = result.get();
assertEquals("john", found.getName());
}
}
jdbc.driverClassName = org.h2.Driver
jdbc.url = jdbc:h2:mem:myDb
hibernate.dialect = org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto = create
h2-datasource.properties
JUnit
Testcontainer
Service Tests mit
TO
HOW
JUnit
@BeforeTestClass
fun initMariaDB() {
val dbContainer: JdbcDatabaseContainer<*> = MariaDBContainer(
DockerImageName.parse("mariadb").withTag("10.4.12"))
}
testImplementation("org.testcontainers:testcontainers-bom:1.17.6")
testImplementation('org.testcontainers:mariadb')
Testcontainer
Service Tests mit
TO
HOW
JUnit
@BeforeTestClass
fun initMariaDB() {
val dbContainer: JdbcDatabaseContainer<*> = MariaDBContainer(
DockerImageName.parse("mariadb").withTag("10.4.12"))
.withExposedPorts(3306)
.withUsername("user")
.withPassword("jug")
}
testImplementation("org.testcontainers:testcontainers-bom:1.17.6")
testImplementation('org.testcontainers:mariadb')
Testcontainer
Service Tests mit
TO
HOW
JUnit
Testcontainer
Service Tests mit
TO
HOW
INFO o.t.d.DockerClientProviderStrategy : Found Docker environment with local Npipe socket (npipe:////./pipe/docker_engine)
INFO org.testcontainers.DockerClientFactory : Docker host IP address is localhost
INFO org.testcontainers.DockerClientFactory : Connected to docker:
Server Version: 20.10.17
API Version: 1.41
Operating System: Docker Desktop
Total Memory: 25605 MB
INFO 🐳 [testcontainers/ryuk:0.3.4] : Creating container for image: testcontainers/ryuk:0.3.4
INFO 🐳 [testcontainers/ryuk:0.3.4] : Container testcontainers/ryuk:0.3.4 is starting: 7985c01359f682cf674c2e6406ae70e9854ade81577590bf5a37b7bdbfbbbe44
INFO 🐳 [testcontainers/ryuk:0.3.4] : Container testcontainers/ryuk:0.3.4 started in PT1.6241543S
INFO o.t.utility.RyukResourceReaper : Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
INFO org.testcontainers.DockerClientFactory : Checking the system...
INFO org.testcontainers.DockerClientFactory : ✔︎ Docker server version should be at least 1.6.0
INFO 🐳 [mariadb:10.4.12] : Creating container for image: mariadb:10.4.12
INFO 🐳 [mariadb:10.4.12] : Container mariadb:10.4.12 is starting: 0d038e95a9f48ef7169ce0542626a91dd72fc32f8cc5639e9c59314ca7fd7f13
INFO 🐳 [mariadb:10.4.12] : Waiting for database connection to become available at jdbc:mariadb://localhost:63608/test using query 'SELECT 1'
INFO 🐳 [mariadb:10.4.12] : Container is started (JDBC URL: jdbc:mariadb://localhost:63608/test)
INFO 🐳 [mariadb:10.4.12] : Container mariadb:10.4.12 started in PT23.6436749S
CompanyRepository
CompanyService
CompanyServiceAPI
Company
Tests which Rock
Layered Service
Lesson
Learned
Maria
DB
CompanyRepository
CompanyService
CompanyServiceAPI
Integartion-Test
Company

Tests, which Rock
Layered Service
Lesson
Learned
Maria
DB
CompanyRepository
CompanyService
CompanyServiceAPI
End-2-End-Test
Company

Tests, which Rock
Layered Service
Lesson
Learned
Maria
DB
CompanyRepository
CompanyService
CompanyServiceAPI
Unit-Test
Company
Tests, which Rock
Layered Service
Lesson
Learned
Maria
DB
CompanyRepository
CompanyService
CompanyServiceAPI
API-Test
Company
Tests, which Rock
Layered Service
Lesson
Learned
Maria
DB
CompanyRepository
CompanyService
CompanyServiceAPI
API-Test
Company
Tests, which Rock
Layered Service
Lesson
Learned
Maria
DB
mocked
CompanyRepository
CompanyService
CompanyServiceAPI
Company
Tests, which Rock
Layered Service
Lesson
Learned
H2
Repository-Test
Lesson
Learned

DOJO Training


