diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eab7b9165e2d8f45dab2bcc436224e03f7bf2795..79314355e02b348b5eff1dc50dcf416d40655048 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,11 +6,11 @@ image: gcc
 
 build:
   stage: build
-  script: 
+  script:
     - echo "It works."
 
 # run tests using the binary built before
 test:
   stage: test
   script:
-    - echo "Running tests."
+    - ./test-ci.sh
diff --git a/quad/lib/test/.gitignore b/quad/lib/test/.gitignore
index 96236f8158b12701d5e75c14fb876c4a0f31b963..abf45b33b86643cbd0623e9265383923ef76e37e 100644
--- a/quad/lib/test/.gitignore
+++ b/quad/lib/test/.gitignore
@@ -1 +1,2 @@
-example
\ No newline at end of file
+example
+test.o
\ No newline at end of file
diff --git a/quad/lib/test/Makefile b/quad/lib/test/Makefile
index d44ec77658faa10b5ba10d42593cb0353d8e55a0..b7b47546af040cb6eb6f326c71cad8026a9878e9 100644
--- a/quad/lib/test/Makefile
+++ b/quad/lib/test/Makefile
@@ -1,5 +1,9 @@
+test.o: test.c
+	gcc -c test.c
+
 example: example.c test.c test.h
 	gcc -g -o example example.c test.c test.h
 
+.PHONY: clean
 clean:
-	rm example
+	rm example test.o
diff --git a/quad/sw/modular_quad_pid/test/.gitignore b/quad/sw/modular_quad_pid/test/.gitignore
index 7f3f794041a5bcf4bea48f1f9a73d757da52297c..f159545885dfb8a7708b4f411522df65889865cf 100644
--- a/quad/sw/modular_quad_pid/test/.gitignore
+++ b/quad/sw/modular_quad_pid/test/.gitignore
@@ -1,3 +1 @@
-uart_buff.c
-uart_buff.h
-test
\ No newline at end of file
+test_uart_buff
\ No newline at end of file
diff --git a/quad/sw/modular_quad_pid/test/Makefile b/quad/sw/modular_quad_pid/test/Makefile
index 5b6f1828dd3f45e06aaf61a0af26ed630b4eb6e3..36613e465ba609b8db63bacd290c279eee14825a 100644
--- a/quad/sw/modular_quad_pid/test/Makefile
+++ b/quad/sw/modular_quad_pid/test/Makefile
@@ -1,7 +1,10 @@
-.PHONY: test
-test:
-	cp ../src/uart_buff.c ../src/uart_buff.h ./
-	gcc -g -o test test_uart_buff.c uart_buff.c
+# QUAD_ROOT is obtained from environment
+SRC = $(QUAD_ROOT)/sw/modular_quad_pid/src
+LIB = $(QUAD_ROOT)/lib/test
 
+test_uart_buff: test_uart_buff.c
+	gcc -o test_uart_buff -I. -I$(SRC) -I$(LIB) $(LIB)/test.o test_uart_buff.c $(SRC)/uart_buff.c
+
+.PHONY: clean
 clean:
-	rm *.o rm *.gch
+	rm test_uart_buff
diff --git a/quad/sw/modular_quad_pid/test/test_uart_buff.c b/quad/sw/modular_quad_pid/test/test_uart_buff.c
index 72eb683edef7662107329a745685c7b26a4610be..db85a701aad5553496357954d8e0df4a6745388b 100644
--- a/quad/sw/modular_quad_pid/test/test_uart_buff.c
+++ b/quad/sw/modular_quad_pid/test/test_uart_buff.c
@@ -2,39 +2,7 @@
 #include "uart_buff.h"
 #include <math.h>
 #include <string.h>
-
-int main() {
-  int failed = 0;
-  failed += test_empty_when_empty();
-  failed += test_empty_after_receiving_some_data();
-  failed += test_full_is_false_at_start();
-  failed += test_full_after_receiving_some_data();
-  failed += test_packet_get_u8();
-  failed += test_packet_get_u8_with_offset();
-  failed += test_packet_get_u16();
-  failed += test_packet_get_u16_with_offset();
-  failed += test_packet_get_u16_wrapped();
-  failed += test_packet_get_u32();
-  failed += test_packet_get_u32_with_offset();
-  failed += test_packet_get_u32_wrapped_1_4();
-  failed += test_packet_get_u32_wrapped_2_4();
-  failed += test_packet_get_u32_wrapped_3_4();
-  failed += test_packet_get_float();
-  failed += test_packet_get_float_with_offset();
-  failed += test_buffer_size_after_VRPN_packet();
-  failed += test_buffer_size_empty();
-  failed += test_buffer_size_after_garbage_data();
-  failed += test_buffer_size_after_garbage_data_scanned();
-  failed += test_packet_ready_at_start();
-  failed += test_packet_ready_after_receiving_packet();
-  failed += test_packet_ready_after_consuming_packet();
-  failed += test_size_when_data_lenth_too_large();
-  failed += test_get_raw();
-
-  printf("Total tests failed: %d\n", failed);
-
-  return 0;
-}
+#include "test.h"
 
 int float_equals(float x1, float x2) {
   return fabs(x1 - x2) < 10e-5;
@@ -69,12 +37,12 @@ void add_packet(u16 type, unsigned short id, unsigned short length, unsigned cha
 void add_VRPN_packet() {
   float arr[6] = {1.0, 1.2, 1.4, -1.5, -0.5, -1.1};
   unsigned char *data = (unsigned char *) &arr;
-  add_packet(4, 0, 0, 24, data);
+  add_packet(4, 0, 24, data);
 }
 
 void add_basic_packet() {
   unsigned char data[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
-  add_packet(4, 0, 0, 6, data);
+  add_packet(4, 0, 6, data);
 }
 
 void add_garbage_data() {
@@ -104,7 +72,6 @@ int test_empty_when_empty() {
   int exp = 1;
   int act = uart_buff_empty();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -114,7 +81,6 @@ int test_empty_after_receiving_some_data() {
   int exp = 0;
   int act = uart_buff_empty();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -123,7 +89,6 @@ int test_full_is_false_at_start() {
   int exp = 0;
   int act = uart_buff_full();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -133,7 +98,6 @@ int test_full_after_receiving_some_data() {
   int exp = 0;
   int act = uart_buff_full();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -142,7 +106,6 @@ int test_buffer_size_empty() {
   int exp = 0;
   int act = uart_buff_size();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -152,7 +115,6 @@ int test_buffer_size_after_garbage_data() {
   int exp = 32;
   int act = uart_buff_size();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -163,7 +125,6 @@ int test_buffer_size_after_garbage_data_scanned() {
   int exp = 0;
   int act = uart_buff_size();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -173,7 +134,6 @@ int test_buffer_size_after_VRPN_packet() {
   int exp = 32;
   int act = uart_buff_size();
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -183,7 +143,6 @@ int test_packet_get_u8() {
   int exp = 0xAA;
   int act = uart_buff_data_get_u8(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -193,7 +152,6 @@ int test_packet_get_u8_with_offset() {
   int exp = 0xBB;
   int act = uart_buff_data_get_u8(1);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -203,7 +161,6 @@ int test_packet_get_u16() {
   int exp = 0xBBAA;
   int act = uart_buff_data_get_u16(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -213,7 +170,6 @@ int test_packet_get_u16_with_offset() {
   int exp = 0xDDCC;
   int act = uart_buff_data_get_u16(2);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -227,7 +183,6 @@ int test_packet_get_u16_wrapped() {
   int exp = 0xBBAA;
   int act = uart_buff_data_get_u16(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -237,7 +192,6 @@ int test_packet_get_u32() {
   unsigned int exp = 0xDDCCBBAA;
   unsigned int act = uart_buff_data_get_u32(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -247,7 +201,6 @@ int test_packet_get_u32_with_offset() {
   unsigned int exp = 0xFFEEDDCC;
   unsigned int act = uart_buff_data_get_u32(2);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -261,7 +214,6 @@ int test_packet_get_u32_wrapped_1_4() {
   int exp = 0xDDCCBBAA;
   int act = uart_buff_data_get_u32(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -275,7 +227,6 @@ int test_packet_get_u32_wrapped_2_4() {
   int exp = 0xDDCCBBAA;
   int act = uart_buff_data_get_u32(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -289,7 +240,6 @@ int test_packet_get_u32_wrapped_3_4() {
   int exp = 0xDDCCBBAA;
   int act = uart_buff_data_get_u32(0);
   int success = exp == act;
-  print_test_result(success, (float) exp, (float) act);
   return !success;
 }
 
@@ -300,7 +250,6 @@ int test_packet_get_float() {
   float exp = 1.0;
   float act = uart_buff_data_get_float(0);
   int success = float_equals(exp, act);
-  print_test_result(success, exp, act);
   return !success;
 }
 
@@ -310,7 +259,6 @@ int test_packet_get_float_with_offset() {
   float exp = 1.2;
   float act = uart_buff_data_get_float(4);
   int success = float_equals(exp, act);
-  print_test_result(success, exp, act);
   return !success;
 }
 
@@ -319,7 +267,6 @@ int test_packet_ready_at_start() {
   int exp = 0;
   int act = uart_buff_packet_ready();
   int success = act == exp;
-  print_test_result(success, exp, act);
   return !success;
 }
 
@@ -329,7 +276,6 @@ int test_packet_ready_after_receiving_packet() {
   int exp = 1;
   int act = uart_buff_packet_ready();
   int success = act == exp;
-  print_test_result(success, exp, act);
   return !success;
 }
 
@@ -340,19 +286,17 @@ int test_packet_ready_after_consuming_packet() {
   int exp = 0;
   int act = uart_buff_packet_ready();
   int success = act == exp;
-  print_test_result(success, exp, act);
   return !success;
 }
 
 int test_size_when_data_lenth_too_large() {
   uart_buff_reset();
   unsigned char data[UART_MAX_PACKET_SIZE + 1];
-  add_packet(4, 0, 0, UART_MAX_PACKET_SIZE + 1, data);
+  add_packet(4, 0, UART_MAX_PACKET_SIZE + 1, data);
   uart_buff_packet_ready();
   int exp = 0;
   int act = uart_buff_size();
   int success = act == exp;
-  print_test_result(success, exp, act);
   return !success;
 }
 
@@ -368,10 +312,37 @@ int test_get_raw() {
   for (i = 0; i < length; i += 1) {
     success = success && (exp[i] == act[i]);
     if (!success) {
-      printf("FAILED");
       break;
     }
   }
-  if (success) printf("passed\n");
   return !success;
 }
+
+int main() {
+  test(test_empty_when_empty, "test empty when empty");
+  test(test_empty_after_receiving_some_data, "test empty after recieving soem data");
+  test(test_full_is_false_at_start, "test full is false at start");
+  test(test_full_after_receiving_some_data, "test full after receiving some data");
+  test(test_packet_get_u8, "test packet get u8");
+  test(test_packet_get_u8_with_offset, "test packet get u8 with offset");
+  test(test_packet_get_u16, "test packet get u16");
+  test(test_packet_get_u16_with_offset, "test packet get u16 wrapped");
+  test(test_packet_get_u16_wrapped, "test packet get u16 wrapped");
+  test(test_packet_get_u32, "test packet get u32");
+  test(test_packet_get_u32_with_offset, "test packet get u32 with offset");
+  test(test_packet_get_u32_wrapped_1_4, "test packet get u32 wrapped 1/4");
+  test(test_packet_get_u32_wrapped_2_4, "test packet get u32 warpped 2/4");
+  test(test_packet_get_u32_wrapped_3_4, "test packet get u32 wrapped 3/4");
+  test(test_packet_get_float, "test packet get u32 wrapped 3/4");
+  test(test_packet_get_float_with_offset, "test packet get float with offset");
+  test(test_buffer_size_after_VRPN_packet, "test buffer size after VRPN packet");
+  test(test_buffer_size_empty, "test buffer size empty");
+  test(test_buffer_size_after_garbage_data, "test buffer size after garbage data");
+  test(test_buffer_size_after_garbage_data_scanned, "test buffer size after garbage data scanned");
+  test(test_packet_ready_at_start, "test packet ready at start");
+  test(test_packet_ready_after_receiving_packet, "test packet ready after receiving packet");
+  test(test_packet_ready_after_consuming_packet, "test packet ready after consuming packet");
+  test(test_size_when_data_lenth_too_large, "test size when data length too large");
+
+  return test_summary();
+}
diff --git a/quad/test-ci.sh b/quad/test-ci.sh
new file mode 100644
index 0000000000000000000000000000000000000000..c35802b3984f5ba6dd4ba5984136340dec297e35
--- /dev/null
+++ b/quad/test-ci.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+QUAD_ROOT=$PROJECT_ROOT/quad
+export QUAD_ROOT
+
+cd $QUAD_ROOT/lib/test
+make || exit 1
+
+cd $QUAD_ROOT/sw/modular_quad_pid/test
+make || exit 1
+./test_uart_buff || exit 1
diff --git a/test-ci.sh b/test-ci.sh
new file mode 100644
index 0000000000000000000000000000000000000000..24c14c1345b77b19c658363a06f2c8e2e2278c29
--- /dev/null
+++ b/test-ci.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+PROJECT_ROOT=$(pwd)
+export PROJECT_ROOT
+
+# Quad
+quad/test-ci.sh || exit 1