diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d7dff93fc42aa404dde32f925e6bf7da84520a79
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,26 @@
+# From: https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml
+image: gradle:8.11.1-jdk23
+
+before_script:
+  - GRADLE_USER_HOME="$(pwd)/.gradle"
+  - export GRADLE_USER_HOME
+
+build:
+  stage: build
+  script: gradle --build-cache assemble
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: push
+    paths:
+      - build
+      - .gradle
+
+test:
+  stage: test
+  script: gradle check
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: pull
+    paths:
+      - build
+      - .gradle
diff --git a/build.gradle.kts b/build.gradle.kts
index 4f670220ea250194a59883db216f54731133d9db..6849c548ac7554bc30dac93bc4d28d5824287a27 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -11,8 +11,9 @@ repositories {
 }
 
 dependencies {
-    testImplementation(platform("org.junit:junit-bom:5.10.0"))
-    testImplementation("org.junit.jupiter:junit-jupiter")
+    testImplementation("org.junit.jupiter:junit-jupiter:5.12.0")
+    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+    testImplementation("org.assertj:assertj-core:3.27.2")
     antlr("org.antlr:antlr4:4.13.2")
 }
 
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 791fe0426a8dbff33feec38a7cd15f9c6ef39b4e..259f84ba60acd25b3341af3e240c2ac3ca8a37fe 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
 #Thu Mar 06 13:04:05 CET 2025
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/src/main/java/sample/attributes/Characters.java b/src/main/java/sample/attributes/Characters.java
index e1a3d9e1397c031f0a8d8467b34f9b9875924f9c..28e77938fa9a9a8a38421531b31f1a6d80466d1b 100644
--- a/src/main/java/sample/attributes/Characters.java
+++ b/src/main/java/sample/attributes/Characters.java
@@ -26,6 +26,9 @@ public class Characters {
     }
 
     private static char getCharacter(String character) {
+        if (character == null) {
+            throw new IllegalArgumentException("Character is null");
+        }
         if(character.length() != 1 ) {
             throw new IllegalArgumentException(character + " is not a character");
         }
diff --git a/src/test/java/sample/attributes/CharactersTest.java b/src/test/java/sample/attributes/CharactersTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..11a5ddb40c5bc5bef61b9a1a89f3e5418c303c05
--- /dev/null
+++ b/src/test/java/sample/attributes/CharactersTest.java
@@ -0,0 +1,35 @@
+package sample.attributes;
+
+import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.*;
+
+public class CharactersTest {
+    @Test
+    void testDepthOf(){
+        assertThat(Characters.depthOf("Z", 10)).isCloseTo(0., withinPercentage(0.001));
+        assertThat(Characters.depthOf("a", 10)).isCloseTo(0., withinPercentage(0.001));
+        assertThat(Characters.depthOf("j", 10)).isCloseTo((3./7)*10, withinPercentage(0.001));
+    }
+
+    @Test
+    void testExceptionDepthOf(){
+        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Characters.depthOf("aa", 10));
+        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Characters.depthOf("", 1));
+        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Characters.depthOf(null, 5));
+    }
+
+    @Test
+    void testHeightOf(){
+        assertThat(Characters.heightOf("G", 100)).isCloseTo(100., withinPercentage(0.001));
+        assertThat(Characters.heightOf("l", 50)).isCloseTo(50., withinPercentage(0.001));
+        assertThat(Characters.heightOf("a", 105)).isCloseTo((4./7)*105, withinPercentage(0.001));
+    }
+
+    @Test
+    void testExceptionHeightOf(){
+        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Characters.heightOf("mm", 10));
+        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Characters.heightOf("", 1));
+        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Characters.heightOf(null, 5));
+    }
+
+}