diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fc22f2e7fdd877df0d95f588d1b5b0ff080a149c..bc53eea36eb16cccb33006b4d6bf4eb669ab2fb8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -66,17 +66,20 @@ minimal-windows:
     - python -c "import numpy"
     - python setup.py quicktest
 
-minimal-ubuntu:
+ubuntu:
   stage: test
   except:
     variables:
       - $ENABLE_NIGHTLY_BUILDS
-  image: i10git.cs.fau.de:5005/pycodegen/pycodegen/minimal_ubuntu
+  image: i10git.cs.fau.de:5005/pycodegen/pycodegen/ubuntu
   script:
+    - mkdir -p ~/.config/matplotlib
+    - echo "backend:template" > ~/.config/matplotlib/matplotlibrc
     - pip3 install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils
-    - python3 setup.py quicktest
+    - pytest-3 -v -m "not longrun"
   tags:
     - docker
+    - cuda
 
 minimal-conda:
   stage: test
diff --git a/conftest.py b/conftest.py
index 743b3562e9e4185a373b97eaaa0fb70813c16c13..3ae58d02970293604366736556a8e85aed0e061a 100644
--- a/conftest.py
+++ b/conftest.py
@@ -46,6 +46,17 @@ except ImportError:
     collect_ignore += [os.path.join(SCRIPT_FOLDER, "lbmpy_tests/test_serial_scenarios.py")]
     collect_ignore += [os.path.join(SCRIPT_FOLDER, "lbmpy_tests/test_datahandling_parallel.py")]
 
+try:
+    import blitzdb
+except ImportError:
+    collect_ignore += [os.path.join(SCRIPT_FOLDER, "lbmpy_tests/benchmark"),
+                       os.path.join(SCRIPT_FOLDER, "lbmpy_tests/full_scenarios/kida_vortex_flow/scenario_kida_vortex_flow.py")]
+
+import sympy
+sver = sympy.__version__.split(".")
+if (int(sver[0]) == 1 and int(sver[1]) < 2):
+    add_path_to_ignore('lbmpy_tests/phasefield')
+    collect_ignore += [os.path.join(SCRIPT_FOLDER, "lbmpy_tests/test_n_phase_boyer_noncoupled.ipynb")]
 
 collect_ignore += [os.path.join(SCRIPT_FOLDER, 'setup.py')]
 
@@ -104,7 +115,7 @@ class IPyNbFile(pytest.File):
         exporter.exclude_markdown = True
         exporter.exclude_input_prompt = True
 
-        notebook_contents = self.fspath.open()
+        notebook_contents = self.fspath.open(encoding='utf-8')
 
         with warnings.catch_warnings():
             warnings.filterwarnings("ignore", "IPython.core.inputsplitter is deprecated")
diff --git a/doc/notebooks/00_tutorial_lbmpy_walberla_overview.ipynb b/doc/notebooks/00_tutorial_lbmpy_walberla_overview.ipynb
index c9ade9495ba519e8214353edb8f7032e6a1e2948..3046074f46e9b859857c4668fb5fc10109195ed4 100644
--- a/doc/notebooks/00_tutorial_lbmpy_walberla_overview.ipynb
+++ b/doc/notebooks/00_tutorial_lbmpy_walberla_overview.ipynb
@@ -1,5 +1,15 @@
 {
  "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pytest\n",
+    "pytest.importorskip('pycuda')"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": 2,
diff --git a/doc/notebooks/01_tutorial_predefinedScenarios.ipynb b/doc/notebooks/01_tutorial_predefinedScenarios.ipynb
index f7bd479c0ff8921750676c2bfb8833b4ca23b7ba..ec02bff6eb754f92c1a0aa33ce432df8e782fc7f 100644
--- a/doc/notebooks/01_tutorial_predefinedScenarios.ipynb
+++ b/doc/notebooks/01_tutorial_predefinedScenarios.ipynb
@@ -1,5 +1,15 @@
 {
  "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pytest\n",
+    "pytest.importorskip('pycuda')"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": 1,
diff --git a/doc/notebooks/demo_moments_cumulants_and_maxwellian_equilibrium.ipynb b/doc/notebooks/demo_moments_cumulants_and_maxwellian_equilibrium.ipynb
index 2a3f401a9816338a0812ab54de343ccf958a26bd..3b147a96e9176179fdc516a6a99f4b367a7c7c2e 100644
--- a/doc/notebooks/demo_moments_cumulants_and_maxwellian_equilibrium.ipynb
+++ b/doc/notebooks/demo_moments_cumulants_and_maxwellian_equilibrium.ipynb
@@ -695,6 +695,16 @@
     "This method for deriving a discrete equilibrium works well for \"full stencils\" i.e. with $3^d$ directions, where $d$ is the dimension."
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pytest\n",
+    "pytest.importorskip('ipy_table')"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": 19,
diff --git a/lbmpy/max_domain_size_info.py b/lbmpy/max_domain_size_info.py
index c8d7458cf6438bda005a5d63ba291db5c9716886..65fa50f97a7401dd37e2d38c037871817e796f56 100644
--- a/lbmpy/max_domain_size_info.py
+++ b/lbmpy/max_domain_size_info.py
@@ -107,9 +107,11 @@ def memory_sizes_of_current_machine():
 
     if get_cpu_info:
         cpu_info = get_cpu_info()
-        result.update({'L1': cpu_info['l1_data_cache_size'],
-                       'L2': cpu_info['l2_cache_size'],
-                       'L3': cpu_info['l3_cache_size']})
+        if 'l1_data_cache_size' in cpu_info:
+            result['L1'] = cpu_info['l1_data_cache_size']
+        result['L2'] = cpu_info['l2_cache_size']
+        if 'l3_cache_size' in cpu_info:
+            result['L3'] = cpu_info['l3_cache_size']
 
     if device:
         size = device.total_memory() / (1024 * 1024)
diff --git a/lbmpy/phasefield_allen_cahn/kernel_equations.py b/lbmpy/phasefield_allen_cahn/kernel_equations.py
index b6904aa90b2900d55358786bab1c5f457efa2572..5f4a690dc0acb724337ac99d2b806646d3740911 100644
--- a/lbmpy/phasefield_allen_cahn/kernel_equations.py
+++ b/lbmpy/phasefield_allen_cahn/kernel_equations.py
@@ -159,11 +159,11 @@ def viscous_force(lb_velocity_field, phi_field, mrt_method, tau, density_heavy,
     eq = np.array(eq)
 
     g_vals = [lb_velocity_field.center(i) for i, _ in enumerate(stencil)]
-    m0 = np.dot(moment_matrix, g_vals)
+    m0 = np.dot(moment_matrix.tolist(), g_vals)
 
     m = m0 - eq
     m = m * rel
-    non_equilibrium = np.dot(moment_matrix.inv(), m)
+    non_equilibrium = np.dot(moment_matrix.inv().tolist(), m)
 
     stress_tensor = [0] * 6
     # Calculate Stress Tensor MRT
@@ -293,7 +293,7 @@ def get_update_rules_velocity(src_field, u_in, lb_method, force, density):
         indices.append(eq.index(first_eqs[i]))
 
     src = [src_field.center(i) for i, _ in enumerate(stencil)]
-    m0 = np.dot(moment_matrix, src)
+    m0 = np.dot(moment_matrix.tolist(), src)
 
     update_u = list()
     update_u.append(Assignment(sp.symbols("rho"), m0[0]))
@@ -356,7 +356,7 @@ def get_collision_assignments_hydro(density=1, optimization=None, **kwargs):
     eq = np.array(eq)
 
     g_vals = [src_field.center(i) for i, _ in enumerate(stencil)]
-    m0 = np.dot(moment_matrix, g_vals)
+    m0 = np.dot(moment_matrix.tolist(), g_vals)
 
     mf = np.zeros(len(stencil), dtype=object)
     for i in range(dimensions):
@@ -374,7 +374,7 @@ def get_collision_assignments_hydro(density=1, optimization=None, **kwargs):
         update_m.append(Assignment(m[i], m0[i] - (m0[i] - eq[i] + mf[i] / 2) * rel[i] + mf[i]))
 
     update_g = list()
-    var = np.dot(moment_matrix.inv(), m)
+    var = np.dot(moment_matrix.inv().tolist(), m)
     if params['kernel_type'] == 'collide_stream_push':
         push_accessor = StreamPushTwoFieldsAccessor()
         post_collision_accesses = push_accessor.write(dst_field, stencil)
diff --git a/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py b/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py
index 09af0c74d3ceda570ef15093b706f60a856d9d97..dc887f7282fb8edd4ef82250e5c331d1741e6323 100644
--- a/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py
+++ b/lbmpy_tests/full_scenarios/shear_wave/scenario_shear_wave.py
@@ -7,6 +7,8 @@
 import numpy as np
 import sympy as sp
 
+import pytest
+
 from lbmpy.creationfunctions import update_with_default_parameters
 from lbmpy.relaxationrates import (
     relaxation_rate_from_lattice_viscosity, relaxation_rate_from_magic_number)
@@ -63,7 +65,7 @@ def plot_y_velocity(vel, **kwargs):
 
 def fit_and_get_slope(x_values, y_values):
     matrix = np.vstack([x_values, np.ones(len(x_values))]).T
-    m, _ = np.linalg.lstsq(matrix, y_values, rcond=None)[0]
+    m, _ = np.linalg.lstsq(matrix, y_values, rcond=1e-14)[0]
     return m
 
 
@@ -212,6 +214,7 @@ def create_full_parameter_study():
 
 
 def test_shear_wave():
+    pytest.importorskip('pycuda')
     params = {
         'l_0': 32,
         'u_0': 0.096,
diff --git a/lbmpy_tests/phasefield/test_nphase_1D.py b/lbmpy_tests/phasefield/test_nphase_1D.py
index ce265386c35110c8ef985de28d68df390ef49f95..71359a97d27a4dffe33bf020220aa8cfe8e441cb 100644
--- a/lbmpy_tests/phasefield/test_nphase_1D.py
+++ b/lbmpy_tests/phasefield/test_nphase_1D.py
@@ -8,7 +8,6 @@ from lbmpy.phasefield.analytical import (
 from lbmpy.phasefield.experiments1D import init_sharp_interface
 from lbmpy.phasefield.scenarios import create_n_phase_model
 from pystencils import create_data_handling, make_slice
-from pystencils.runhelper import ParameterStudy
 
 
 def extract_profile(sc, width, phase_idx=1):
@@ -111,6 +110,7 @@ def study_1d(study):
 
 
 if __name__ == '__main__':
+    from pystencils.runhelper import ParameterStudy
     s = ParameterStudy(run_n_phase_1d)
     study_1d(s)
     s.run_from_command_line()
diff --git a/lbmpy_tests/phasefield/test_nphase_2D.py b/lbmpy_tests/phasefield/test_nphase_2D.py
index 7d4359d90a1e09ce3494ff5175cafc2393cec56e..0254c944649ec503a86fa2d6539c20c5f0e8aa5f 100644
--- a/lbmpy_tests/phasefield/test_nphase_2D.py
+++ b/lbmpy_tests/phasefield/test_nphase_2D.py
@@ -9,7 +9,6 @@ from lbmpy.phasefield.contact_angle_circle_fitting import liquid_lens_neumann_an
 from lbmpy.phasefield.post_processing import analytic_neumann_angles
 from lbmpy.phasefield.scenarios import create_n_phase_model, create_three_phase_model
 from pystencils import create_data_handling, make_slice
-from pystencils.runhelper import ParameterStudy
 from pystencils.utils import boolean_array_bounding_box
 
 color = {'yellow': '\033[93m',
@@ -209,6 +208,7 @@ def study_2d(study, **kwargs):
 
 
 def main():
+    from pystencils.runhelper import ParameterStudy
     s = ParameterStudy(run_n_phase_2d)
     # study_3phase(s)
     study_2d(s)
diff --git a/lbmpy_tests/test_boundary_handling.py b/lbmpy_tests/test_boundary_handling.py
index 25589c2cd76a91c6f0b0db90e0fff58ce2c7433b..cc88ffa696c0c881321ee6a0d373365b70c87592 100644
--- a/lbmpy_tests/test_boundary_handling.py
+++ b/lbmpy_tests/test_boundary_handling.py
@@ -1,5 +1,7 @@
 import numpy as np
 
+import pytest
+
 from lbmpy.boundaries import UBB, NeumannByCopy, NoSlip, StreamInConstant
 from lbmpy.boundaries.boundaryhandling import LatticeBoltzmannBoundaryHandling
 from lbmpy.creationfunctions import create_lb_function
@@ -8,9 +10,12 @@ from lbmpy.lbstep import LatticeBoltzmannStep
 from pystencils import create_data_handling, make_slice
 
 
-def test_simple():
+@pytest.mark.parametrize("gpu", [True, False])
+def test_simple(gpu):
+    import pytest
+    pytest.importorskip('pycuda')
     dh = create_data_handling((10, 5), parallel=False)
-    dh.add_array('pdfs', values_per_cell=9, cpu=True, gpu=True)
+    dh.add_array('pdfs', values_per_cell=9, cpu=True, gpu=gpu)
     lb_func = create_lb_function(stencil='D2Q9', compressible=False, relaxation_rate=1.8)
 
     bh = LatticeBoltzmannBoundaryHandling(lb_func.method, dh, 'pdfs')
diff --git a/lbmpy_tests/test_html_output.py b/lbmpy_tests/test_html_output.py
index d1a7f8df8a89c3e94160f78eea7ee08934a11ede..66050072f9f8c94cdc7ae3f9b135fdbc96edb544 100644
--- a/lbmpy_tests/test_html_output.py
+++ b/lbmpy_tests/test_html_output.py
@@ -1,3 +1,5 @@
+import pytest
+
 from lbmpy.creationfunctions import create_lb_method
 from lbmpy.methods.creationfunctions import compare_moment_based_lb_methods
 from lbmpy.moments import (
@@ -6,6 +8,7 @@ from lbmpy.stencils import get_stencil
 
 
 def test_moment_comparison_table():
+    pytest.importorskip('ipy_table')
     new = create_lb_method(stencil='D3Q19', maxwellian_moments=True)
     old = create_lb_method(stencil='D3Q19', maxwellian_moments=False)
 
@@ -25,6 +28,7 @@ def test_moment_comparison_table():
 
 
 def test_moment_equality_table():
+    pytest.importorskip('ipy_table')
     d3q19 = get_stencil('D3Q19')
     table1 = moment_equality_table(d3q19, max_order=3)
     assert len(table1.array) == 5
diff --git a/lbmpy_tests/test_n_phase_boyer_noncoupled.ipynb b/lbmpy_tests/test_n_phase_boyer_noncoupled.ipynb
index 328fbc9e55b34079bb5b4ea75b95435a95ac5f19..888e2e29f7c6419c3dc90caf51a73ceec0c12744 100644
--- a/lbmpy_tests/test_n_phase_boyer_noncoupled.ipynb
+++ b/lbmpy_tests/test_n_phase_boyer_noncoupled.ipynb
@@ -1,5 +1,15 @@
 {
  "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pytest\n",
+    "pytest.importorskip('pycuda')"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": 1,
@@ -360,7 +370,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.6.8"
+   "version": "3.6.9"
   }
  },
  "nbformat": 4,
diff --git a/lbmpy_tests/test_plot.py b/lbmpy_tests/test_plot.py
index 2c5e138611041fe621b56e25c36278978ae34014..d6d521101aeb502dd2d9bb98adba14b905bb3a57 100644
--- a/lbmpy_tests/test_plot.py
+++ b/lbmpy_tests/test_plot.py
@@ -1,5 +1,8 @@
 import os
 from tempfile import TemporaryDirectory
+import shutil
+
+import pytest
 
 import numpy as np
 
@@ -7,6 +10,7 @@ import lbmpy.plot as plt
 from lbmpy.scenarios import create_lid_driven_cavity
 
 
+@pytest.mark.skipif(shutil.which('ffmpeg') is None, reason="ffmpeg not available")
 def test_animation():
 
     ldc = create_lid_driven_cavity((10, 10), relaxation_rate=1.8)