diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 396a29b7bf0d8d282e37416b1224ec6d592170da..4f99d127ddd22f6133c5942d4c8e46c6af1a725e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,6 +28,7 @@ stages:
   - cert
   - style
   - test
+  - deploy
 
 
 # During the test stage the CI pipeline (which runs in a "root" docker) starts
@@ -123,6 +124,11 @@ test:
       - cd .docker
         # here the server and the mysql backend docker are being started
       - CAOSDB_TAG=$CAOSDB_TAG docker-compose  up -d
+        # store versions of CaosDB parts
+      - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_pylib_commit > hash_pylib
+      - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_webui_commit > hash_webui
+      - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_server_commit > hash_server
+      - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_mysqlbackend_commit > hash_mysql
         # the pyinttest docker writes the return value of the tests into the
         # file result
       - /bin/sh ./run.sh
@@ -138,7 +144,7 @@ test:
     paths:
       - caosdb_log.txt
       - mariadb_log.txt
-    when: on_failure
+      - .docker/hash_*
     expire_in: 1 week
 
 build-testenv:
@@ -193,3 +199,25 @@ style:
   script:
       - autopep8 -r --diff --exit-code .
   allow_failure: true
+
+
+store-version:
+  tags: [docker]
+  stage: deploy
+  dependencies: [test]
+  image: $CI_REGISTRY_IMAGE
+  script:
+      - curl -u gitlab:$REVISONSTOREPW
+        --data server=$(cat .docker/hash_server)
+        --data mysql=$(cat .docker/hash_mysql)
+        --data pylib=$(cat .docker/hash_pylib)
+        --data webui=$(cat .docker/hash_webui)
+        --data save=1 https://caosdb.org/revisions/saverev.php
+  allow_failure: true
+  only:
+    - dev
+    - master
+    # TODO remove
+    - f-versions
+    - web
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0682590eca1a575646eeed6084849e88c27a0b68..54331f5ebb34f4b9af7c3592358a62dc5e1d5b2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed (for changes in existing functionality)
 
+* Tests comply with the new entity error handling (see
+  [#32](https://gitlab.com/caosdb/caosdb-pylib/-/issues/32) in
+  caosdb-pylib).
 * `test_recursive_parents.py` now tests inserted entities; set to
   xfail until
   [caosdb-pylib#34](https://gitlab.com/caosdb/caosdb-pylib/-/issues/34)
@@ -36,6 +39,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Removed (for now removed features)
 
+- Some redundant tests from `test_tickets.py` that checked
+  functionality that was already tested in `test_error_stuff.py`.
+
 ### Fixed (for any bug fixes)
 
 * Tests for NaN Double Values (see https://gitlab.com/caosdb/caosdb-server/issues/41)
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000000000000000000000000000000000000..529a96a81c76e6d2607e1cddcc79024981d3cc56
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,4 @@
+[pytest]
+markers =
+    local_server: mark a test as requiring a local caosdb server
+    slow: mark a test as slow (execution regularly takes 5s or longer)
diff --git a/tests/test_administration.py b/tests/test_administration.py
index 9ca57c659079f7f3b6cbd39a4b83a89f53621f20..9ecc1360dc537852463c8ab3c2abc945266711e2 100644
--- a/tests/test_administration.py
+++ b/tests/test_administration.py
@@ -27,12 +27,12 @@
 """
 
 from caosdb import administration as admin
-from caosdb import get_config
 from caosdb.connection.connection import configure_connection, get_connection
-from caosdb.exceptions import (AuthorizationException, ClientErrorException,
-                               LoginFailedException, TransactionError)
+from caosdb.exceptions import (HTTPClientError, HTTPForbiddenError,
+                               LoginFailedError, HTTPResourceNotFoundError)
 from nose.tools import (assert_equal, assert_is_not_none, assert_raises,
                         assert_true)
+from pytest import raises
 
 test_role = "test_role"
 test_user = "test_user"
@@ -104,16 +104,14 @@ def test_insert_role_success():
 
 def test_insert_role_failure_permission():
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._insert_role(name=test_role, description=test_role_desc)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to insert a new role.")
+    assert cm.value.msg == "You are not permitted to insert a new role."
 
 
 def test_insert_role_failure_name_duplicates():
     test_insert_role_success()
-    with assert_raises(ClientErrorException) as cm:
+    with assert_raises(HTTPClientError) as cm:
         admin._insert_role(name=test_role, description=test_role_desc)
     assert_equal(
         cm.exception.msg,
@@ -132,17 +130,15 @@ def test_update_role_success():
 def test_update_role_failure_permissions():
     test_insert_role_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._update_role(name=test_role, description=test_role_desc + "asdf")
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to update this role.")
+    assert cm.value.msg == "You are not permitted to update this role."
 
 
 def test_update_role_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._update_role(name=test_role, description=test_role_desc + "asdf")
-    assert_equal(cm.exception.msg, "Role does not exist.")
+    assert cm.value.msg == "Role does not exist."
 
 
 def test_delete_role_success():
@@ -153,17 +149,15 @@ def test_delete_role_success():
 def test_delete_role_failure_permissions():
     test_insert_role_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._delete_role(name=test_role)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to delete this role.")
+    assert cm.value.msg == "You are not permitted to delete this role."
 
 
 def test_delete_role_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._delete_role(name=test_role)
-    assert_equal(cm.exception.msg, "Role does not exist.")
+    assert cm.value.msg == "Role does not exist."
 
 
 def test_retrieve_role_success():
@@ -175,17 +169,15 @@ def test_retrieve_role_success():
 def test_retrieve_role_failure_permission():
     test_insert_role_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._retrieve_role(name=test_role)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to retrieve this role.")
+    assert cm.value.msg == "You are not permitted to retrieve this role."
 
 
 def test_retrieve_role_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._retrieve_role(name=test_role)
-    assert_equal(cm.exception.msg, "Role does not exist.")
+    assert cm.value.msg == "Role does not exist."
 
 
 def test_set_permissions_success():
@@ -202,23 +194,21 @@ def test_set_permissions_success():
 def test_set_permissions_failure_permissions():
     test_insert_role_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._set_permissions(
             role=test_role, permission_rules=[
                 admin.PermissionRule(
                     "Grant", "BLA:BLA:BLA")])
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to set this role's permissions.")
+    assert cm.value.msg == "You are not permitted to set this role's permissions."
 
 
 def test_set_permissions_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._set_permissions(
             role=test_role, permission_rules=[
                 admin.PermissionRule(
                     "Grant", "BLA:BLA:BLA")])
-    assert_equal(cm.exception.msg, "Role does not exist.")
+    assert cm.value.msg == "Role does not exist."
 
 
 def test_get_permissions_success():
@@ -231,17 +221,15 @@ def test_get_permissions_success():
 def test_get_permissions_failure_permissions():
     test_set_permissions_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._get_permissions(role=test_role)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to retrieve this role's permissions.")
+    assert cm.value.msg == "You are not permitted to retrieve this role's permissions."
 
 
 def test_get_permissions_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._get_permissions(role="non-existing-role")
-    assert_equal(cm.exception.msg, "Role does not exist.")
+    assert cm.value.msg == "Role does not exist."
 
 
 def test_get_roles_success():
@@ -255,17 +243,15 @@ def test_get_roles_success():
 def test_get_roles_failure_permissions():
     test_insert_role_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._get_roles(username=test_user)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to retrieve this user's roles.")
+    assert cm.value.msg == "You are not permitted to retrieve this user's roles."
 
 
 def test_get_roles_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._get_roles(username="non-existing-user")
-    assert_equal(cm.exception.msg, "User does not exist.")
+    assert cm.value.msg == "User does not exist."
 
 
 def test_set_roles_success():
@@ -290,16 +276,14 @@ def test_set_roles_failure_permissions():
     roles = {test_role}
     roles.union(roles_old)
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._set_roles(username=test_user, roles=roles_old)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to set this user's roles.")
+    assert cm.value.msg == "You are not permitted to set this user's roles."
 
 
 def test_set_roles_failure_non_existing_role():
     roles = {"non-existing-role"}
-    with assert_raises(ClientErrorException) as cm:
+    with assert_raises(HTTPClientError) as cm:
         admin._set_roles(username=test_user, roles=roles)
     assert_equal(cm.exception.msg, "Role does not exist.")
 
@@ -307,9 +291,9 @@ def test_set_roles_failure_non_existing_role():
 def test_set_roles_failure_non_existing_user():
     test_insert_role_success()
     roles = {test_role}
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._set_roles(username="non-existing-user", roles=roles)
-    assert_equal(cm.exception.msg, "User does not exist.")
+    assert cm.value.msg == "User does not exist."
 
 
 def test_insert_user_success():
@@ -323,21 +307,19 @@ def test_insert_user_success():
 
 def test_insert_user_failure_permissions():
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._insert_user(
             name=test_user,
             password="secret1P!",
             status="ACTIVE",
             email="email@example.com",
             entity=None)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to insert a new user.")
+    assert cm.value.msg == "You are not permitted to insert a new user."
 
 
 def test_insert_user_failure_name_in_use():
     test_insert_user_success()
-    with assert_raises(ClientErrorException) as cm:
+    with assert_raises(HTTPClientError) as cm:
         test_insert_user_success()
     assert_equal(cm.exception.msg, "User name is already in use.")
 
@@ -350,17 +332,15 @@ def test_delete_user_success():
 def test_delete_user_failure_permissions():
     test_insert_user_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._delete_user(name="non_existing_user")
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to delete this user.")
+    assert cm.value.msg == "You are not permitted to delete this user."
 
 
 def test_delete_user_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._delete_user(name="non_existing_user")
-    assert_equal(cm.exception.msg, "User does not exist.")
+    assert cm.value.msg == "User does not exist."
 
 
 def test_update_user_success_status():
@@ -427,15 +407,12 @@ def test_update_user_success_password():
 
 
 def test_update_user_failure_permissions_status():
-    assert_is_not_none(
-        admin._insert_user(
-            name=test_user + "2",
-            password="secret1P!",
-            status="INACTIVE",
-            email="email@example.com",
-            entity=None))
+    assert admin._insert_user(name=test_user + "2",
+                              password="secret1P!",
+                              status="INACTIVE",
+                              email="email@example.com", entity=None) is not None
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._update_user(
             realm=None,
             name=test_user + "2",
@@ -443,21 +420,15 @@ def test_update_user_failure_permissions_status():
             status="ACTIVE",
             email=None,
             entity=None)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to update this user.")
+    assert cm.value.msg == "You are not permitted to update this user."
 
 
 def test_update_user_failure_permissions_email():
-    assert_is_not_none(
-        admin._insert_user(
-            name=test_user + "2",
-            password="secret1P!",
-            status="ACTIVE",
-            email="email@example.com",
-            entity=None))
+    assert admin._insert_user(name=test_user + "2",
+                              password="secret1P!", status="ACTIVE",
+                              email="email@example.com", entity=None) is not None
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._update_user(
             realm=None,
             name=test_user + "2",
@@ -465,21 +436,15 @@ def test_update_user_failure_permissions_email():
             status=None,
             email="newemail@example.com",
             entity=None)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to update this user.")
+    assert cm.value.msg == "You are not permitted to update this user."
 
 
 def test_update_user_failure_permissions_entity():
-    assert_is_not_none(
-        admin._insert_user(
-            name=test_user + "2",
-            password="secret1P!",
-            status="ACTIVE",
-            email="email@example.com",
-            entity=None))
+    assert admin._insert_user(name=test_user + "2",
+                              password="secret1P!", status="ACTIVE",
+                              email="email@example.com", entity=None) is not None
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._update_user(
             realm=None,
             name=test_user + "2",
@@ -487,21 +452,15 @@ def test_update_user_failure_permissions_entity():
             status=None,
             email=None,
             entity=21)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to update this user.")
+    assert cm.value.msg == "You are not permitted to update this user."
 
 
 def test_update_user_failure_permissions_password():
-    assert_is_not_none(
-        admin._insert_user(
-            name=test_user + "2",
-            password="secret1P!",
-            status="ACTIVE",
-            email="email@example.com",
-            entity=None))
+    assert admin._insert_user(name=test_user + "2",
+                              password="secret1P!", status="ACTIVE",
+                              email="email@example.com", entity=None) is not None
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._update_user(
             realm=None,
             name=test_user + "2",
@@ -509,13 +468,11 @@ def test_update_user_failure_permissions_password():
             status=None,
             email=None,
             entity=None)
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to update this user.")
+    assert cm.value.msg == "You are not permitted to update this user."
 
 
 def test_update_user_failure_non_existing_user():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._update_user(
             realm=None,
             name="non-existing-user",
@@ -523,18 +480,14 @@ def test_update_user_failure_non_existing_user():
             status="ACTIVE",
             email="email@example.com",
             entity=None)
-    assert_equal(cm.exception.msg, "User does not exist.")
+    assert cm.value.msg == "User does not exist."
 
 
 def test_update_user_failure_non_existing_entity():
-    assert_is_not_none(
-        admin._insert_user(
-            name=test_user + "2",
-            password="secret1P!",
-            status="ACTIVE",
-            email="email@example.com",
-            entity=None))
-    with assert_raises(ClientErrorException) as cm:
+    assert admin._insert_user(name=test_user + "2",
+                              password="secret1P!", status="ACTIVE",
+                              email="email@example.com", entity=None) is not None
+    with raises(HTTPClientError) as cm:
         admin._update_user(
             realm=None,
             name=test_user + "2",
@@ -542,7 +495,7 @@ def test_update_user_failure_non_existing_entity():
             status=None,
             email=None,
             entity=100000)
-    assert_equal(cm.exception.msg, "Entity does not exist.")
+    assert cm.value.msg == "Entity does not exist."
 
 
 def test_retrieve_user_success():
@@ -553,17 +506,15 @@ def test_retrieve_user_success():
 def test_retrieve_user_failure_permissions():
     test_insert_user_success()
     switch_to_normal_user()
-    with assert_raises(AuthorizationException) as cm:
+    with raises(HTTPForbiddenError) as cm:
         admin._retrieve_user(realm=None, name=test_user + "2")
-    assert_equal(
-        cm.exception.msg,
-        "You are not permitted to retrieve this user.")
+    assert cm.value.msg == "You are not permitted to retrieve this user."
 
 
 def test_retrieve_user_failure_non_existing():
-    with assert_raises(TransactionError) as cm:
+    with raises(HTTPResourceNotFoundError) as cm:
         admin._retrieve_user(realm=None, name="non_existing")
-    assert_equal(cm.exception.msg, "User does not exist.")
+    assert cm.value.msg == "User does not exist."
 
 
 def test_login_with_inactive_user_failure():
@@ -576,5 +527,5 @@ def test_login_with_inactive_user_failure():
             entity=None))
     configure_connection(username=test_user + "2", password="secret1P!",
                          password_method="plain")
-    with assert_raises(LoginFailedException):
+    with assert_raises(LoginFailedError):
         get_connection()._login()
diff --git a/tests/test_affiliation.py b/tests/test_affiliation.py
index 0b9f011d04708f68dd21e9059dac6bc23a5a159d..bdd73d117488ceb09210fdcdc0a92ba3b0794c3e 100644
--- a/tests/test_affiliation.py
+++ b/tests/test_affiliation.py
@@ -25,9 +25,10 @@
 
 @author: tf
 """
-import caosdb as db
 import os
-from nose.tools import nottest, assert_true, assert_raises, assert_equal, with_setup, assert_is_not_none  # @UnresolvedImport
+import caosdb as db
+from nose.tools import nottest, assert_true, assert_equal, with_setup, assert_is_not_none
+from pytest import raises
 
 
 def setup_module():
@@ -85,31 +86,33 @@ def test_rec_rt_is_instantiation():
 
 @with_setup(setup, teardown)
 def test_rec_prop_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.Record(name="TestRecordChild").add_parent(name=prop_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    # TransactionError with UnqualifiedParentsError with EntityError
+    # caused by wrong affiliation
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
 def test_rec_file_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.Record(name="TestRecordChild").add_parent(name=file_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
 def test_rt_rec_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.RecordType(
             name="TestRecordTypeChild").add_parent(
             name=rec_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
@@ -121,48 +124,48 @@ def test_rt_rt_is_subtyping():
 
 @with_setup(setup, teardown)
 def test_rt_prop_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.RecordType(
             name="TestRecordTypeChild").add_parent(
             name=prop_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
 def test_rt_file_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.RecordType(
             name="TestRecordTypeChild").add_parent(
             name=file_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
 def test_prop_rec_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.Property(
             name="TestPropertyChild",
             datatype=db.TEXT).add_parent(
             name=rec_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
 def test_prop_rt_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.Property(
             name="TestPropertyChild",
             datatype=db.TEXT).add_parent(
             name=recty_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
@@ -176,14 +179,14 @@ def test_prop_prop_is_subtyping():
 
 @with_setup(setup, teardown)
 def test_prop_file_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.Property(
             name="TestPropertyChild",
             datatype=db.TEXT).add_parent(
             name=file_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
@@ -208,28 +211,28 @@ def test_file_rt_is_instantiation():
 
 @with_setup(setup, teardown)
 def test_file_prop_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.File(
             name="TestFileChild",
             file=file_path,
             path="testfilechild.dat").add_parent(
             name=prop_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @with_setup(setup, teardown)
 def test_file_file_is_invalid():
-    with assert_raises(db.EntityError) as cm:
+    with raises(db.TransactionError) as cm:
         db.File(
             name="TestFileChild",
             file=file_path,
             path="testfilechild.dat").add_parent(
             name=file_name).insert()
-    assert_equal(
-        cm.exception.get_errors()[0].msg,
-        "Affiliation is not defined for this child-parent constellation.")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    ee = cm.value.errors[0].errors[0]
+    assert ee.msg == "Affiliation is not defined for this child-parent constellation."
 
 
 @nottest
diff --git a/tests/test_authentication.py b/tests/test_authentication.py
index ce2a095bab5f6b2d70afbea1a2a96af624c71389..ef0657cbe215743e79ce1e2110a1b172cb980c36 100644
--- a/tests/test_authentication.py
+++ b/tests/test_authentication.py
@@ -33,7 +33,7 @@ import ssl
 from subprocess import call
 from lxml import etree
 from pytest import raises, mark
-from caosdb.exceptions import LoginFailedException
+from caosdb.exceptions import LoginFailedError
 import caosdb as db
 from .test_server_side_scripting import request
 
@@ -86,7 +86,7 @@ def test_https_support():
 
 
 def test_login_via_post_form_data_failure():
-    with raises(LoginFailedException):
+    with raises(LoginFailedError):
         db.get_connection().post_form_data(
             "login", {
                 "username": db.get_config().get("Connection", "username"),
@@ -145,6 +145,7 @@ def test_login_while_anonymous_is_active():
         "/Response/UserInfo/Roles/Role")[0].text == "administration"
 
 
+@mark.local_server
 def test_authtoken_config():
     assert db.administration.get_server_property(
         "AUTHTOKEN_CONFIG") == "conf/core/authtoken.example.yaml"
@@ -174,6 +175,7 @@ def get_one_time_token(testcase):
     return auth_token
 
 
+@mark.local_server
 def test_one_time_token():
     assert db.Info().user_info.roles == ["administration"]
     assert db.Info().user_info.name == db.get_config().get("Connection", "username")
@@ -193,13 +195,14 @@ def test_one_time_token():
                                                            "username")
 
 
+@mark.local_server
 def test_one_time_token_invalid():
     auth_token = get_one_time_token("admin_token_crud")
     auth_token = auth_token.replace("[]", '["permission"]')
 
     db.configure_connection(password_method="auth_token",
                             auth_token=auth_token)
-    with raises(db.LoginFailedException) as lfe:
+    with raises(db.LoginFailedError) as lfe:
         db.Info()
     assert lfe.value.args[0] == (
         "The authentication token is expired or you have been logged out otherwise. The auth_token "
@@ -210,18 +213,19 @@ def test_one_time_token_invalid():
     db.administration.set_server_property("AUTH_OPTIONAL", "TRUE")
     db.configure_connection(password_method="auth_token",
                             auth_token=auth_token)
-    with raises(db.LoginFailedException) as lfe:
+    with raises(db.LoginFailedError) as lfe:
         db.Info()
     assert lfe.value.args[0] == (
         "The authentication token is expired or you have been logged out otherwise. The auth_token "
         "authenticator cannot log in again. You must provide a new authentication token.")
 
 
+@mark.local_server
 def test_one_time_token_expired():
     auth_token = get_one_time_token("admin_token_expired")
     db.configure_connection(password_method="auth_token",
                             auth_token=auth_token)
-    with raises(db.LoginFailedException) as lfe:
+    with raises(db.LoginFailedError) as lfe:
         db.Info()
     assert lfe.value.args[0] == (
         "The authentication token is expired or you have been logged out otherwise. The auth_token "
@@ -232,13 +236,14 @@ def test_one_time_token_expired():
     db.administration.set_server_property("AUTH_OPTIONAL", "TRUE")
     db.configure_connection(password_method="auth_token",
                             auth_token=auth_token)
-    with raises(db.LoginFailedException) as lfe:
+    with raises(db.LoginFailedError) as lfe:
         db.Info()
     assert lfe.value.args[0] == (
         "The authentication token is expired or you have been logged out otherwise. The auth_token "
         "authenticator cannot log in again. You must provide a new authentication token.")
 
 
+@mark.local_server
 def test_one_time_token_3_attempts():
     auth_token = get_one_time_token("admin_token_3_attempts")
 
@@ -273,7 +278,7 @@ def test_one_time_token_3_attempts():
     db.configure_connection(password_method="auth_token",
                             auth_token=auth_token)
     assert db.get_connection()._authenticator.auth_token == auth_token
-    with raises(db.LoginFailedException) as lfe:
+    with raises(db.LoginFailedError) as lfe:
         db.Info()
     assert lfe.value.args[0] == (
         "The authentication token is expired or you have been logged out otherwise. The auth_token "
@@ -286,13 +291,14 @@ def test_one_time_token_3_attempts():
     db.configure_connection(password_method="auth_token",
                             auth_token=auth_token)
     assert db.get_connection()._authenticator.auth_token == auth_token
-    with raises(db.LoginFailedException) as lfe:
+    with raises(db.LoginFailedError) as lfe:
         db.Info()
     assert lfe.value.args[0] == (
         "The authentication token is expired or you have been logged out otherwise. The auth_token "
         "authenticator cannot log in again. You must provide a new authentication token.")
 
 
+@mark.local_server
 def test_crud_with_one_time_token():
     auth_token = get_one_time_token("admin_token_crud")
     db.configure_connection(password_method="auth_token",
diff --git a/tests/test_boolean.py b/tests/test_boolean.py
index 60ad1cbd80d34a6892fcdd3304e0b401840a02e2..296dfab0be6524461861f58d4e5eb26087463b8f 100644
--- a/tests/test_boolean.py
+++ b/tests/test_boolean.py
@@ -28,8 +28,9 @@
 
 import caosdb as h
 # @UnresolvedImport
-from nose.tools import assert_true, assert_equal, assert_false, assert_raises
-from caosdb.exceptions import EntityError
+from nose.tools import assert_true, assert_equal, assert_false
+from caosdb.exceptions import TransactionError
+from pytest import raises
 
 
 def test_property():
@@ -126,7 +127,8 @@ def test_record():
         rec3 = h.Record(
             name="SimpleRecord3").add_parent(rt).add_property(
             p.name, value="BLABLA")
-        assert_raises(EntityError, rec3.insert)
+        with raises(TransactionError):
+            rec3.insert()
 
         assert_false(rec3.is_valid())
         assert_equal(
diff --git a/tests/test_datatype.py b/tests/test_datatype.py
index ce800b49b8c12f6a949a48489b5ac9e00ee1010c..56dd247eb54b31b3f7e798684d35b29576b9c7ad 100644
--- a/tests/test_datatype.py
+++ b/tests/test_datatype.py
@@ -54,7 +54,9 @@ def test_override_with_non_existing_ref():
             name="TestProperty",
             datatype=rt2,
             value="Non-Existing").add_parent(rt1).insert()
-    assert cm.value.get_errors()[0].msg == "Referenced entity does not exist."
+    assert cm.value.has_error(db.UnqualifiedPropertiesError)
+    assert (cm.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
 
 def test_override_with_existing_ref():
@@ -139,29 +141,23 @@ def test_generic_reference_failure():
 
 def test_unknown_datatype1():
     p = db.Property(name="TestP", datatype="Non-Existing")
-    try:
+    with raises(db.TransactionError) as te:
         p.insert()
-        assert False is True
-    except db.TransactionError as e:
-        assert e.msg == "Unknown datatype."
+    assert te.value.errors[0].msg == "Unknown datatype."
 
 
 def test_unknown_datatype2():
     p = db.Property(name="TestP", datatype="12345687654334567")
-    try:
+    with raises(db.TransactionError) as te:
         p.insert()
-        assert False is True
-    except db.TransactionError as e:
-        assert e.msg == "Unknown datatype."
+    assert te.value.errors[0].msg == "Unknown datatype."
 
 
 def test_unknown_datatype3():
     p = db.Property(name="TestP", datatype="-134")
-    try:
+    with raises(db.TransactionError) as te:
         p.insert()
-        assert False is True
-    except db.TransactionError as e:
-        assert e.msg == "Unknown datatype."
+    assert te.value.errors[0].msg == "Unknown datatype."
 
 
 def test_wrong_refid():
@@ -169,10 +165,10 @@ def test_wrong_refid():
     rt2 = db.RecordType(name="TestRT2").insert()
     rt3 = db.RecordType(name="TestRT3").insert()
     p = db.Property(name="TestP1", datatype=rt1.id).insert()
-    assert p.is_valid() is True
-    assert rt1.is_valid() is True
-    assert rt2.is_valid() is True
-    assert rt3.is_valid() is True
+    assert p.is_valid()
+    assert rt1.is_valid()
+    assert rt2.is_valid()
+    assert rt3.is_valid()
 
     rec1 = db.Record().add_parent(name="TestRT1").insert()
     rec2 = db.Record().add_parent(name="TestRT2").insert()
@@ -180,20 +176,18 @@ def test_wrong_refid():
         name="TestRT3").add_property(
         name="TestP1",
         value=rec2.id)
-    try:
+    with raises(db.TransactionError):
         rec3.insert()
-        assert False is True
-    except db.TransactionError:
-        desc = ('Reference not qualified. The value of this Reference '
-                'Property is to be a child of its data type.')
-        err = rec3.get_property("TestP1").get_errors()[0]
-        assert err.description == desc
+    desc = ('Reference not qualified. The value of this Reference '
+            'Property is to be a child of its data type.')
+    err = rec3.get_property("TestP1").get_errors()[0]
+    assert err.description == desc
 
     rec4 = db.Record().add_parent(
         name="TestRT3").add_property(
         name="TestP1",
         value=rec1.id).insert()
-    assert rec4.is_valid() is True
+    assert rec4.is_valid()
 
 
 def test_datatype_mismatch_in_response():
@@ -210,4 +204,4 @@ def test_datatype_mismatch_in_response():
     with raises(db.TransactionError) as exc:
         # should not raise ValueError but transaction error.
         rt.insert()
-    assert exc.value.get_errors()[0].msg == "Cannot parse value to double."
+    assert exc.value.errors[0].errors[0].msg == "Cannot parse value to double."
diff --git a/tests/test_datatype_inheritance.py b/tests/test_datatype_inheritance.py
index eba41766c8a989c6abefe335ab488ccdbea716f6..307d6c48b5b8583893b315156f11038d271ebd16 100644
--- a/tests/test_datatype_inheritance.py
+++ b/tests/test_datatype_inheritance.py
@@ -28,7 +28,8 @@ from caosdb.connection.connection import get_connection
 # @UnresolvedImport
 from nose.tools import assert_is_not_none, assert_true, assert_equal, with_setup
 
-from caosdb.exceptions import EntityError
+from caosdb.exceptions import TransactionError
+from pytest import raises
 
 
 def setup():
@@ -150,12 +151,11 @@ def test_datatype_overriding_update():
             str("TEXT").lower(),
             rt.get_properties()[0].datatype.lower())
 
-        try:
+        with raises(TransactionError) as te:
             p.datatype = "INT"
             p.update()
-            raise AssertionError("This should raise an EntityError!")
-        except EntityError as e:
-            assert_equal("Unknown datatype.", e.msg)
+
+        assert "Unknown datatype." == te.value.errors[0].msg
 
         p.datatype = "INTEGER"
         p.update()
diff --git a/tests/test_datetime.py b/tests/test_datetime.py
index cda35a1f013833744f314fda6a5bd87547cda5b9..b6254d5d5930e2cce0f659a6013c9e499406e59d 100644
--- a/tests/test_datetime.py
+++ b/tests/test_datetime.py
@@ -26,6 +26,7 @@
 @author: tf
 """
 
+import pytest
 from nose.tools import assert_true, assert_false  # @UnresolvedImport
 import caosdb as h
 
@@ -136,6 +137,7 @@ def test_date_storage():
             pass
 
 
+@pytest.mark.slow
 def test_in_operator():
     try:
         rec = set_up_rec()
@@ -438,6 +440,7 @@ def test_in_operator():
             pass
 
 
+@pytest.mark.slow
 def test_not_in_operator():
     try:
         rec = set_up_rec()
@@ -778,6 +781,7 @@ def test_not_in_operator():
             pass
 
 
+@pytest.mark.slow
 def test_eq_operator():
     try:
         rec = set_up_rec()
@@ -844,6 +848,7 @@ def test_eq_operator():
             pass
 
 
+@pytest.mark.slow
 def test_neq_operator():
     try:
         rec = set_up_rec()
@@ -912,6 +917,7 @@ def test_neq_operator():
             pass
 
 
+@pytest.mark.slow
 def test_smaller_operator():
     try:
         rec = set_up_rec()
@@ -1166,6 +1172,7 @@ def test_smaller_operator():
             pass
 
 
+@pytest.mark.slow
 def test_greater_operator():
     try:
         rec = set_up_rec()
@@ -1420,6 +1427,7 @@ def test_greater_operator():
             pass
 
 
+@pytest.mark.slow
 def test_greater_equal_operator():
     try:
         rec = set_up_rec()
@@ -1673,6 +1681,7 @@ def test_greater_equal_operator():
             pass
 
 
+@pytest.mark.slow
 def test_smaller_equal_operator():
     try:
         rec = set_up_rec()
diff --git a/tests/test_error_stuff.py b/tests/test_error_stuff.py
index 5e2e11837d5ede6a330252751da3eff61bcc1ea5..d6eb85b74bf288e91de02c4d6d95e1f1298b2c0f 100644
--- a/tests/test_error_stuff.py
+++ b/tests/test_error_stuff.py
@@ -5,6 +5,8 @@
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+# Copyright (C) 2020 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -21,367 +23,320 @@
 #
 # ** end header
 #
-"""Created on 19.02.2015.
+"""Test different entity errors.
+
+Created on 19.02.2015.
 
 @author: tf
+
 """
-from caosdb.exceptions import EntityDoesNotExistError, UniqueNamesError,\
-    TransactionError, EntityError, UnqualifiedPropertiesError,\
-    EntityHasNoDatatypeError, UnqualifiedParentsError
+import caosdb as h
+from caosdb.exceptions import (AmbiguousEntityError,
+                               EntityDoesNotExistError, EntityError,
+                               EntityHasNoDatatypeError,
+                               TransactionError, UniqueNamesError,
+                               UnqualifiedParentsError,
+                               UnqualifiedPropertiesError)
+import pytest
 
 
-def test_retrieval_no_exception_raised():
-    import caosdb as h
-    from nose.tools import assert_true, assert_false  # @UnresolvedImport
+def setup():
+    try:
+        h.execute_query("FIND Test*").delete()
+    except BaseException:
+        pass
 
-    p = h.Property(name="Non-ExsistentProperty").retrieve(unique=True,
-                                                          raise_exception_on_error=False)
-    assert_false(p.is_valid())
-    assert_true(p.id is None or p.id < 0)
 
+def teardown():
+    """Delete everything."""
+    setup()
 
-def test_retrieval_exception_raised():
-    import caosdb as h
-    from nose.tools import assert_true, assert_is_not_none, assert_equal  # @UnresolvedImport
 
-    # special error: EntityDoesNotExistError
-    try:
-        h.Property(name="Non-ExistentProperty").retrieve(unique=True,
-                                                         raise_exception_on_error=True)
-        assert_true(False)
-    except EntityDoesNotExistError as e:
-        print("print(" + str(id(e)) + ")")
-        print(e)
-        assert_is_not_none(e.get_entity())
-
-    # more general error: EntityError
-    try:
-        h.Property(name="Non-ExistentProperty").retrieve(unique=True,
-                                                         raise_exception_on_error=True)
-        assert_true(False)
-    except EntityError as e:
-        print(e)
-        assert_is_not_none(e.get_entity())
-        assert_equal('Non-ExistentProperty', e.get_entity().name)
-
-    # most general error: TransactionError
-    try:
-        h.Property(name="Non-ExistentProperty").retrieve(unique=True,
-                                                         raise_exception_on_error=True)
-        assert_true(False)
-    except EntityDoesNotExistError as e:
-        print(e)
-        assert_is_not_none(e.get_entities())
-        print(e.get_entities())
-        assert_is_not_none(e.get_entity())
-        print(e.get_entity())
-        assert_equal(1, len(e.get_entities()))
-        assert_equal('Non-ExistentProperty', e.get_entities()[0].name)
+def test_retrieval_no_exception_raised():
+    """Test whether retrieval fails but error is suppressed."""
+    p = h.Property(name="TestNon-ExsistentProperty").retrieve(
+        unique=True, raise_exception_on_error=False)
+    assert not p.is_valid()
+    assert (p.id is None or p.id < 0)
 
 
-def test_insertion_no_exception_raised():
-    import caosdb as h
-    from nose.tools import assert_false, assert_true  # @UnresolvedImport
+def test_retrieval_exception_raised():
+    """Test if a TransactionError with the correct child is raised, and if
+    the child has the correct super classes.
+
+    """
+    propname = "TestNon-ExistentProperty"
+    with pytest.raises(TransactionError) as te:
+        h.Property(name="TestNon-ExistentProperty").retrieve(unique=True,
+                                                             raise_exception_on_error=True)
+    assert len(te.value.errors) == 1
+    ee = te.value.errors[0]
+    # Check for type incl. inheritance
+    assert isinstance(ee, EntityDoesNotExistError)
+    assert isinstance(ee, EntityError)
+    assert isinstance(ee, TransactionError)
+    # Correct entity causing the error:
+    assert ee.entity is not None
+    assert ee.entity.name == propname
+    assert not ee.entity.is_valid()
+    assert ee.entity.has_errors()
+
+
+@pytest.mark.xfail(reason=("Error treatment on server-side"
+                           "has to be implemented first."))
+def test_ambiguous_retrieval():
+    """Test if a TransactionError containing an AmbiguousEntityError is
+    raised correctly if there are two possible candidates.
+
+    """
+    h.RecordType(name="TestType").insert()
+    h.Record(name="TestRec").add_parent(name="TestType").insert()
+    # Insert twice, so unique=False
+    h.Record(name="TestRec").add_parent(name="TestType").insert(unique=False)
+    with pytest.raises(TransactionError) as te:
+        h.Record(name="TestRec").retrieve()
+    assert te.value.has_error(AmbiguousEntityError)
+    assert te.value.errors[0].entity.name == "TestRec"
 
-    try:
-        p = h.Property(
-            name="NoTypeProperty").insert(
-            raise_exception_on_error=False)
-        assert_false(p.is_valid())
-        assert_true(p.id is None or p.id < 0)
-    finally:
-        try:
-            p.delete()
-        except BaseException:
-            pass
 
+def test_insertion_no_exception_raised():
+    """Test whether insertion fails but no error is raised."""
+    p = h.Property(name="TestNoTypeProperty").insert(
+        raise_exception_on_error=False)
+    assert not p.is_valid()
+    assert (p.id is None or p.id < 0)
 
-def test_insertion_exception_raised():
-    import caosdb as h
-    from nose.tools import assert_true  # @UnresolvedImport
 
-    try:
-        p = h.Property(name="NoTypeProperty")
+def test_insertion_exception_raised():
+    """Test insertion of a property with missing datatype."""
+    p = h.Property(name="TestNoTypeProperty")
+    with pytest.raises(TransactionError) as te:
         p.insert(raise_exception_on_error=True)
-        assert_true(False)
-    except EntityError as e:
-        print(e)
-    finally:
-        try:
-            p.delete()
-        except BaseException:
-            pass
+    assert te.value.has_error(EntityHasNoDatatypeError)
 
 
 def test_insertion_with_invalid_parents():
-    import caosdb as h
-    # @UnresolvedImport
-    from nose.tools import assert_false, assert_true, assert_is_not_none, assert_equal
-
-    try:
+    with pytest.raises(TransactionError) as te:
         p = h.Property(
-            name="NoTypeProperty",
+            name="TestNoTypeProperty",
             datatype="Text").add_parent(
             id=-1)
         p.insert(raise_exception_on_error=True)
-        assert_true(False)
-    except EntityError as e:
-        print(e)
-        assert_true(isinstance(e, UnqualifiedParentsError))
-        assert_is_not_none(e.get_entity())
-        assert_equal(e.get_entity().name, p.name)
-        assert_equal(e.get_entity().id, p.id)
-        assert_true(e.get_entity().has_errors())
-        assert_false(p.is_valid())
-        assert_false(e.get_entity().is_valid())
-        assert_is_not_none(e.get_entities())
-    finally:
-        try:
-            p.delete()
-        except BaseException:
-            pass
+    upe = te.value.errors[0]
+    print(upe)
+    assert isinstance(upe, UnqualifiedParentsError)
+    assert upe.entity is not None
+    assert upe.entity.name == p.name
+    assert upe.entity.id == p.id
+    assert upe.entity.has_errors()
+    assert not p.is_valid()
+    assert not upe.entity.is_valid()
+    assert upe.entities is not None
 
 
 def test_insertion_with_invalid_properties():
-    import caosdb as h
-    # @UnresolvedImport
-    from nose.tools import assert_false, assert_true, assert_is_not_none, assert_equal
-
-    try:
-        try:
-            h.execute_query("FIND NoTypeProperty").delete()
-        except BaseException:
-            pass
+    with pytest.raises(TransactionError) as te:
         p = h.Property(
-            name="NoTypeProperty",
+            name="TestNoTypeProperty",
             datatype="Text").add_property(
             id=-1)
         p.insert(raise_exception_on_error=True)
-        raise AssertionError(
-            "This should raise an UnqualifiedPropertiesError.")
-    except EntityError as e:
-        assert_true(isinstance(e, UnqualifiedPropertiesError))
-        assert_is_not_none(e.get_entity())
-        assert_equal(e.get_entity().name, p.name)
-        assert_true(e.get_entity().has_errors())
-        assert_true(p.has_errors())
-        assert_false(p.is_valid())
-        assert_false(e.get_entity().is_valid())
-    finally:
-        try:
-            p.delete()
-        except BaseException:
-            pass
+    upe = te.value.errors[0]
+    assert isinstance(upe, UnqualifiedPropertiesError)
+    assert upe.entity is not None
+    assert upe.entity.name == p.name
+    assert upe.entity.has_errors()
+    assert p.has_errors()
+    assert not p.is_valid()
+    assert not upe.entity.is_valid()
 
 
 def test_entity_does_not_exist():
-    import caosdb as h
-    # @UnresolvedImport
-    from nose.tools import assert_true, assert_false, assert_equal, assert_is_not_none
+    """When retrieving a container with existing and non-existing
+    entities, only those that don't exist should cause
+    EntityDoesNotExistErrors.
+
+    """
+    p1 = h.Property(name="TestNon-ExistentProperty1").retrieve(
+        raise_exception_on_error=False)
+    p2 = h.Property(name="TestNon-ExistentProperty2").retrieve(
+        raise_exception_on_error=False)
+    p3 = h.Property(name="TestNon-ExistentProperty3").retrieve(
+        raise_exception_on_error=False)
+    # None of them should exist
+    assert not p1.is_valid()
+    assert (p1.id is None or p1.id < 0)
+    assert not p2.is_valid()
+    assert (p2.id is None or p2.id < 0)
+    assert not p3.is_valid()
+    assert (p3.id is None or p3.id < 0)
+
+    pe = h.Property(name="TestExistentProperty", datatype="text").insert()
+
+    c = h.Container().extend(
+        [
+            h.Property(
+                name="TestNon-ExistentProperty1"),
+            h.Property(
+                name="TestNon-ExistentProperty2"),
+            h.Property(
+                name="TestNon-ExistentProperty3"),
+            h.Property(
+                name="TestExistentProperty")])
 
-    try:
-        p1 = h.Property(
-            name="Non-ExistentProperty1").retrieve(raise_exception_on_error=False)
-        p2 = h.Property(
-            name="Non-ExistentProperty2").retrieve(raise_exception_on_error=False)
-        p3 = h.Property(
-            name="Non-ExistentProperty3").retrieve(raise_exception_on_error=False)
-        assert_false(p1.is_valid())
-        assert_true(p1.id is None or p1.id < 0)
-        assert_false(p2.is_valid())
-        assert_true(p2.id is None or p2.id < 0)
-        assert_false(p3.is_valid())
-        assert_true(p3.id is None or p3.id < 0)
-
-        pe = h.Property(name="ExistentProperty", datatype="text").insert()
-
-        c = h.Container().extend(
-            [
-                h.Property(
-                    name="Non-ExistentProperty1"),
-                h.Property(
-                    name="Non-ExistentProperty2"),
-                h.Property(
-                    name="Non-ExistentProperty3"),
-                h.Property(
-                    name="ExistentProperty")])
-
-        try:
-            c.retrieve()
-        except EntityDoesNotExistError as e:
-            assert_equal(3, len(e.get_entities()))
-            for entity in e.get_entities():
-                assert_is_not_none(entity.name)
-                assert_true(entity.name.startswith("Non-ExistentProperty"))
-    finally:
-        try:
-            pe.delete()
-        except BaseException:
-            pass
+    with pytest.raises(TransactionError) as te:
+        c.retrieve()
+    te = te.value
+    assert te.has_error(EntityDoesNotExistError)
+    # Only non-existing entities caused the container error
+    assert not pe.name in [x.name for x in te.all_entities]
+    for p in (p1, p2, p3):
+        assert p.name in [x.name for x in te.all_entities]
 
 
 def test_insert_existent_entity():
-    import caosdb as h
-    # @UnresolvedImport
-    from nose.tools import assert_true, assert_false, assert_equal, assert_is_not_none
+    """Insertion of an already existing entity should cause a
+    UniqueNamesError.
+
+    """
+    p1 = h.Property(name="TestNon-ExistentProperty1").retrieve(
+        raise_exception_on_error=False)
+    p2 = h.Property(name="TestNon-ExistentProperty2").retrieve(
+        raise_exception_on_error=False)
+    p3 = h.Property(name="TestNon-ExistentProperty3").retrieve(
+        raise_exception_on_error=False)
+    # None of them should exist
+    assert not p1.is_valid()
+    assert (p1.id is None or p1.id < 0)
+    assert not p2.is_valid()
+    assert (p2.id is None or p2.id < 0)
+    assert not p3.is_valid()
+    assert (p3.id is None or p3.id < 0)
+
+    pe = h.Property(name="TestExistentProperty", datatype="text").insert()
+    assert pe.is_valid()
+
+    c = h.Container().extend(
+        [
+            h.Property(
+                name="TestNon-ExistentProperty1",
+                datatype="text"),
+            h.Property(
+                name="TestNon-ExistentProperty2",
+                datatype="text"),
+            h.Property(
+                name="TestNon-ExistentProperty3",
+                datatype="text"),
+            h.Property(
+                name="TestExistentProperty",
+                datatype="text")])
 
-    try:
-        p1 = h.Property(
-            name="Non-ExistentProperty1").retrieve(raise_exception_on_error=False)
-        p2 = h.Property(
-            name="Non-ExistentProperty2").retrieve(raise_exception_on_error=False)
-        p3 = h.Property(
-            name="Non-ExistentProperty3").retrieve(raise_exception_on_error=False)
-        assert_false(p1.is_valid())
-        assert_true(p1.id is None or p1.id < 0)
-        assert_false(p2.is_valid())
-        assert_true(p2.id is None or p2.id < 0)
-        assert_false(p3.is_valid())
-        assert_true(p3.id is None or p3.id < 0)
-
-        pe = h.Property(name="ExistentProperty", datatype="text").insert()
-        assert_true(pe.is_valid())
-
-        c = h.Container().extend(
-            [
-                h.Property(
-                    name="Non-ExistentProperty1",
-                    datatype="text"),
-                h.Property(
-                    name="Non-ExistentProperty2",
-                    datatype="text"),
-                h.Property(
-                    name="Non-ExistentProperty3",
-                    datatype="text"),
-                h.Property(
-                    name="ExistentProperty",
-                    datatype="text")])
-
-        try:
-            c.insert(unique=True)
-        except UniqueNamesError as e:
-            assert_equal(1, len(e.get_entities()))
-            for entity in e.get_entities():
-                assert_is_not_none(entity.name)
-                assert_equal(pe.name, entity.name)
-
-    finally:
-        try:
-            c.delete()
-        except BaseException:
-            pass
-        try:
-            pe.delete()
-        except BaseException:
-            pass
-        try:
-            p3.delete()
-        except BaseException:
-            pass
-        try:
-            p2.delete()
-        except BaseException:
-            pass
-        try:
-            p1.delete()
-        except BaseException:
-            pass
+    with pytest.raises(TransactionError) as te:
+        c.insert(unique=True)
+    te = te.value
+    assert te.has_error(UniqueNamesError)
+    une = te.errors[0]
+    assert une.entity is not None
+    assert pe.name == une.entity.name
+    for p in (p1, p2, p3):
+        assert p not in te.all_entities
 
 
 def test_double_insertion():
-    import caosdb as h
-    from nose.tools import assert_true, assert_equal, assert_is_not_none  # @UnresolvedImport
-
     c1 = h.Container()
-    try:
-        c1.append(
-            h.Property(
-                name="SimpleTextProperty",
-                description="simple text property (from test_error_stuff.py)",
-                datatype='text'))
-        c1.append(
-            h.Property(
-                name="SimpleDoubleProperty",
-                description="simple double property (from test_error_stuff.py)",
-                datatype='double'))
-        c1.append(
-            h.Property(
-                name="SimpleIntegerProperty",
-                description="simple integer property (from test_error_stuff.py)",
-                datatype='integer'))
-        c1.append(
-            h.Property(
-                name="SimpleDatetimeProperty",
-                description="simple datetime property (from test_error_stuff.py)",
-                datatype='datetime'))
-
-        c1.append(
-            h.RecordType(
-                name="SimpleRecordType",
-                description="simple recordType (from test_error_stuff.py)") .add_property(
-                name='SimpleTextProperty') .add_property(
-                name='SimpleDoubleProperty') .add_property(
-                    name='SimpleIntegerProperty') .add_property(
-                        name='SimpleDatetimeProperty'))
-
-        c1.insert()
-
-        c2 = h.Container()
-        c2.append(
-            h.Property(
-                name="SimpleTextProperty",
-                description="simple text property (from test_error_stuff.py)",
-                datatype='text'))
-        c2.append(
-            h.Property(
-                name="SimpleDoubleProperty",
-                description="simple double property (from test_error_stuff.py)",
-                datatype='double'))
-        c2.append(
-            h.Property(
-                name="SimpleIntegerProperty",
-                description="simple integer property (from test_error_stuff.py)",
-                datatype='integer'))
-        c2.append(
-            h.Property(
-                name="SimpleDatetimeProperty",
-                description="simple datetime property (from test_error_stuff.py)",
-                datatype='datetime'))
-
-        c2.append(
-            h.RecordType(
-                name="SimpleRecordType",
-                description="simple recordType (from test_error_stuff.py)") .add_property(
-                name='SimpleTextProperty') .add_property(
-                name='SimpleDoubleProperty') .add_property(
-                    name='SimpleIntegerProperty') .add_property(
-                        name='SimpleDatetimeProperty'))
-        try:
-            c2.insert()
-        except TransactionError as te:
-            assert_true(isinstance(te, EntityError))
-            assert_true(isinstance(te, UniqueNamesError))
-            assert_true(hasattr(te, 'get_errors'))
-            assert_is_not_none(te.get_errors)
-            assert_is_not_none(te.get_errors())
-            assert_true(hasattr(te, 'get_error'))
-            assert_is_not_none(te.get_error)
-            assert_is_not_none(te.get_error())
-            assert_true(hasattr(te, 'get_entities'))
-            assert_is_not_none(te.get_entities)
-            assert_is_not_none(te.get_entities())
-            assert_equal(5, len(te.get_entities()))
-            assert_true(hasattr(te, 'get_container'))
-            assert_is_not_none(te.get_container)
-            assert_is_not_none(te.get_container())
-            assert_equal(c2, te.get_container())
-
-    finally:
-        try:
-            c2.delete()
-        except BaseException:
-            pass
-        try:
-            c1.delete()
-        except BaseException:
-            pass
+
+    c1.append(
+        h.Property(
+            name="TestSimpleTextProperty",
+            description="simple text property (from test_error_stuff.py)",
+            datatype='text'))
+    c1.append(
+        h.Property(
+            name="TestSimpleDoubleProperty",
+            description="simple double property (from test_error_stuff.py)",
+            datatype='double'))
+    c1.append(
+        h.Property(
+            name="TestSimpleIntegerProperty",
+            description="simple integer property (from test_error_stuff.py)",
+            datatype='integer'))
+    c1.append(
+        h.Property(
+            name="TestSimpleDatetimeProperty",
+            description="simple datetime property (from test_error_stuff.py)",
+            datatype='datetime'))
+
+    c1.append(
+        h.RecordType(
+            name="TestSimpleRecordType",
+            description="simple recordType (from test_error_stuff.py)").add_property(
+                name='TestSimpleTextProperty').add_property(
+                    name='TestSimpleDoubleProperty').add_property(
+                        name='TestSimpleIntegerProperty').add_property(
+                            name='TestSimpleDatetimeProperty'))
+
+    c1.insert()
+
+    c2 = h.Container()
+    c2.append(
+        h.Property(
+            name="TestSimpleTextProperty",
+            description="simple text property (from test_error_stuff.py)",
+            datatype='text'))
+    c2.append(
+        h.Property(
+            name="TestSimpleDoubleProperty",
+            description="simple double property (from test_error_stuff.py)",
+            datatype='double'))
+    c2.append(
+        h.Property(
+            name="TestSimpleIntegerProperty",
+            description="simple integer property (from test_error_stuff.py)",
+            datatype='integer'))
+    c2.append(
+        h.Property(
+            name="TestSimpleDatetimeProperty",
+            description="simple datetime property (from test_error_stuff.py)",
+            datatype='datetime'))
+
+    c2.append(
+        h.RecordType(
+            name="TestSimpleRecordType",
+            description="simple recordType (from test_error_stuff.py)").add_property(
+                name='TestSimpleTextProperty').add_property(
+                    name='TestSimpleDoubleProperty').add_property(
+                        name='TestSimpleIntegerProperty').add_property(
+                            name='TestSimpleDatetimeProperty'))
+    with pytest.raises(TransactionError) as te:
+        c2.insert()
+    te = te.value
+    assert te.has_error(UniqueNamesError)
+    # c2 caused the ContainerError
+    assert te.container == c2
+    # exactly 5 faulty entities in c2
+    assert len(te.entities) == 5
+
+
+def test_update_acl_errors():
+    """Test the special cases of entity errors when using
+    `Entity.update_acl`
+
+    """
+    rec_ne = h.Record("TestRecordNonExisting")
+
+    with pytest.raises(TransactionError) as te:
+
+        rec_ne.update_acl()
+
+    assert te.value.has_error(EntityDoesNotExistError)
+    assert te.value.errors[0].entity.name == rec_ne.name
+
+    rt = h.RecordType(name="TestType").insert()
+    rec = h.Record(name="TestRecord").add_parent(rt).insert()
+    h.Record(name=rec.name).add_parent(rt).insert(unique=False)
+
+    with pytest.raises(TransactionError) as te:
+
+        h.Record(name=rec.name).update_acl()
+
+    assert te.value.has_error(AmbiguousEntityError)
diff --git a/tests/test_file.py b/tests/test_file.py
index 4dbf4fd9a25e20378294c6f519154c1b25a16c54..354fee19c9ed4a0498c7e9562ff200f76f1530b6 100644
--- a/tests/test_file.py
+++ b/tests/test_file.py
@@ -33,16 +33,12 @@ from random import randint
 from sys import maxsize as maxint
 
 from lxml import etree
-from pytest import raises
-from nose.tools import (assert_equal, assert_false,  # @UnresolvedImport
-                        assert_is_not_none, assert_raises, assert_true,
-                        nottest)
-
-from caosdb import Info
-from caosdb import administration as admin
+from pytest import raises, mark
+from nose.tools import (assert_equal, assert_false, assert_is_not_none,
+                        assert_true)
 from caosdb import execute_query, get_config, get_connection
 from caosdb.common import models
-from caosdb.exceptions import EntityError
+from caosdb.exceptions import EntityError, TransactionError
 from caosdb.utils.checkFileSystemConsistency import runCheck
 
 
@@ -92,6 +88,7 @@ def test_file_with_space():
     qfile.download("test2.dat")
 
 
+@mark.local_server
 def test_pickup_file():
     d = models.DropOffBox()
     d.sync()
@@ -111,6 +108,7 @@ def test_pickup_file():
         assert_is_not_none(file_.id)
 
 
+@mark.local_server
 def test_pickup_folder():
     # pickup_folder
     d = models.DropOffBox()
@@ -137,6 +135,7 @@ def test_pickup_folder():
         file_.insert()
 
 
+@mark.local_server
 def test_file4():
     try:
         d = models.DropOffBox()
@@ -241,9 +240,10 @@ def test_file6():
                 path="testfiles2/",
                 pickup=path)
 
-            with raises(EntityError) as cm:
+            with raises(TransactionError) as te:
                 folder_.insert()
-            errors = cm.value.entity.get_errors()
+            cm = te.value.errors[0]
+            errors = cm.entity.get_errors()
             assert errors[0].description == 'This target path does already exist.'
     finally:
         try:
@@ -300,7 +300,9 @@ def test_file7():
                 path="testfiles2/",
                 pickup="path")
 
-            assert_raises(EntityError, folder_.insert)
+            with raises(TransactionError) as te:
+                folder_.insert()
+            assert te.value.has_error(EntityError)
     finally:
         try:
             folder_.delete()
@@ -490,6 +492,7 @@ def test_insert_files_in_dir_error1():
     assert_true(c.messages["Error", 0][0].startswith("Dir is not allowed"))
 
 
+@mark.local_server
 def test_insert_files_in_dir_with_symlink():
     path = get_config().get("IntegrationTests",
                             "test_files.test_insert_files_in_dir.local") + "testfolder/"
@@ -566,6 +569,7 @@ def test_insert_files_in_dir_with_symlink():
             pass
 
 
+@mark.local_server
 def test_insert_files_in_dir():
     """ test if files in directories can be inserted as symlinks via the
     InsertFilesInDir flag. This tests also verifies that the job can be
@@ -665,6 +669,7 @@ def test_insert_files_in_dir():
             pass
 
 
+@mark.local_server
 def test_insert_files_in_dir_regex():
     path = get_config().get("IntegrationTests",
                             "test_files.test_insert_files_in_dir.local") + "testfolder/"
diff --git a/tests/test_issues_server.py b/tests/test_issues_server.py
index bb3a3490837687483bfc564d9f255feb7a1b4478..b5c16cb0edc031ac865e57a5bb84874447566481 100644
--- a/tests/test_issues_server.py
+++ b/tests/test_issues_server.py
@@ -29,7 +29,7 @@ import tempfile
 import time
 
 import caosdb as db
-from caosdb.exceptions import EntityError, TransactionError
+from caosdb.exceptions import TransactionError
 import pytest
 
 
@@ -94,7 +94,7 @@ def test_issue_62():
     assert prop.datatype == rtb.name  # fails; datatype not updated
     # Can't use Test_RTA as datatype anymore
     prop2 = db.Property(name="Test_Prop2", datatype="Test_RTA")
-    with pytest.raises(EntityError):
+    with pytest.raises(TransactionError):
         prop2.insert()
 
 
@@ -143,6 +143,7 @@ def test_issue_85_b():
     C.update()  # Failed at this step
 
 
+@pytest.mark.local_server
 def test_issue_99():
     """Checksum updating failed with versioning enabled.
     """
diff --git a/tests/test_list.py b/tests/test_list.py
index 17f9e5baae10215f86a35cd28015548ae6a30607..98a7bb6fae1bb5940c05e4f9d2ce8e1611f5c69a 100644
--- a/tests/test_list.py
+++ b/tests/test_list.py
@@ -27,9 +27,10 @@
 """
 import os
 import caosdb as db
-from caosdb.exceptions import TransactionError
-from nose.tools import nottest, assert_true, assert_raises, assert_equal
-from pytest import mark
+from caosdb.exceptions import (TransactionError,
+                               UnqualifiedPropertiesError)
+from nose.tools import assert_true, assert_equal
+from pytest import raises
 
 
 def setup():
@@ -63,9 +64,9 @@ def test_list_of_files():
                 db.FILE),
             value=[
                 file_.id]).insert()
-    assert_true(rec.is_valid())
+    assert rec.is_valid()
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.Record(
             name="TestRecNotOk").add_parent(recty).add_property(
                 name="TestListProperty",
@@ -73,9 +74,9 @@ def test_list_of_files():
                     db.FILE),
                 value=[
                     p.id]).insert()
-    assert_equal(
-        tr_err.exception.errors[0].msg,
-        "Reference not qualified. The value of this Reference Property is to be a child of its data type.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Reference not qualified. The value of this Reference Property is to be a child of its data type.")
 
 
 def test_list_datatype_know():
@@ -205,36 +206,35 @@ def test_error_on_wrong_value():
             db.INTEGER)).insert()
     assert_true(p.is_valid())
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT").add_property(
                 name="TestListProperty",
                 value=["this is not an int"]).insert()
-    assert_equal(tr_err.exception.msg, "Entity has unqualified properties.")
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Cannot parse value to integer.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Cannot parse value to integer.")
 
 
 def test_data_type_with_non_existing_ref1():
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.Property(name="TestListProperty",
                     datatype=db.LIST("non_existing")).insert()
-    assert_equal(tr_err.exception.msg, "Unknown datatype.")
+    assert tr_err.value.errors[0].msg == "Unknown datatype."
 
 
 def test_data_type_with_non_existing_ref2():
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.Property(
             name="TestListProperty",
             datatype=db.LIST(234233234)).insert()
-    assert_equal(tr_err.exception.msg, "Unknown datatype.")
+    assert tr_err.value.errors[0].msg == "Unknown datatype."
 
 
 def test_data_type_with_non_existing_ref3():
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.Property(name="TestListProperty", datatype=db.LIST(-2341)).insert()
-    assert_equal(tr_err.exception.msg, "Unknown datatype.")
+    assert tr_err.value.errors[0].msg == "Unknown datatype."
 
 
 def test_data_type_with_existing_ref1():
@@ -373,44 +373,45 @@ def test_single_ref_value_scope_error():
     rt2 = db.RecordType(name="TestRT2").insert()
     db.Property(name="TestProp", datatype=db.LIST(rt2)).insert()
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT3").add_property(
                 name="TestProp",
                 value=[rec]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Reference not qualified. The value of this Reference Property is to be a child of its data type.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Reference not qualified. The value of this Reference " +
+            "Property is to be a child of its data type.")
 
 
 def test_error_single_non_existing_ref_value():
     rt = db.RecordType(name="TestRT").insert()
     db.Property(name="TestProp", datatype=db.LIST(rt)).insert()
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT2").add_property(
                 name="TestProp",
                 value=["non_existing"]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Referenced entity does not exist.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT2").add_property(
                 name="TestProp",
                 value=[213425234234]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Referenced entity does not exist.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(name="TestRT2").add_property(
             name="TestProp", value=[-1234]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Referenced entity does not exist.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
 
 def test_error_multi_non_existing_ref_value():
@@ -419,7 +420,7 @@ def test_error_multi_non_existing_ref_value():
     db.Record(name="TestRec2").add_parent(name="TestRT").insert()
     db.Property(name="TestProp", datatype=db.LIST(rt)).insert()
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT2").add_property(
                 name="TestProp",
@@ -427,11 +428,11 @@ def test_error_multi_non_existing_ref_value():
                     "TestRec1",
                     "non_existing",
                     "TestRec2"]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Referenced entity does not exist.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT2").add_property(
             name="TestProp",
@@ -439,18 +440,18 @@ def test_error_multi_non_existing_ref_value():
                     213425234234,
                     "TestRec2",
                     "TestRec1"]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Referenced entity does not exist.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT2").add_property(
                 name="TestProp", value=[
                     "TestRec1", "TestRec2", -1234]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Referenced entity does not exist.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Referenced entity does not exist.")
 
 
 def test_multi_ref_value_scope_error():
@@ -462,7 +463,7 @@ def test_multi_ref_value_scope_error():
     db.Record(name="TestRec2").add_parent(name="TestRT2").insert()
     db.Property(name="TestProp", datatype=db.LIST(rt2)).insert()
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.RecordType(
             name="TestRT3").add_property(
                 name="TestProp",
@@ -470,9 +471,10 @@ def test_multi_ref_value_scope_error():
                     rec,
                     "TestRec1",
                     "TestRec2"]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        "Reference not qualified. The value of this Reference Property is to be a child of its data type.")
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            "Reference not qualified. The value of this Reference " +
+            "Property is to be a child of its data type.")
 
 
 def test_multi_ref_value():
@@ -635,37 +637,38 @@ def test_list_of_references():
             name="Test_RT1",
             datatype=db.LIST("Test_RT1")).insert()
     p = rt2.get_properties()[0]
-    assert_equal(p.id, rt1.id)
-    assert_equal(p.name, rt1.name)
-    assert_equal(p.datatype, db.LIST(rt1.name))
+    assert p.id == rt1.id
+    assert p.name == rt1.name
+    assert p.datatype == db.LIST(rt1.name)
 
     p = db.execute_query("FIND Test_RT2", unique=True).get_properties()[0]
-    assert_equal(p.id, rt1.id)
-    assert_equal(p.name, rt1.name)
-    assert_equal(p.datatype, db.LIST(rt1.name))
+    assert p.id == rt1.id
+    assert p.name == rt1.name
+    assert p.datatype == db.LIST(rt1.name)
 
     rt1rec1 = db.Record(name="Test_RT1_Rec1").add_parent("Test_RT1").insert()
-    assert_true(rt1rec1.is_valid())
+    assert rt1rec1.is_valid()
 
-    with assert_raises(TransactionError) as tr_err:
+    with raises(TransactionError) as tr_err:
         db.Record(
             name="Test_RT2_Rec").add_parent("Test_RT2").add_property(
                 name="Test_RT1",
                 value=[rt1rec1]).insert()
-    assert_equal(
-        tr_err.exception.get_errors()[0].msg,
-        'This datatype does not accept collections of values (e.g. Lists).')
+    print(tr_err.value)
+    assert tr_err.value.has_error(UnqualifiedPropertiesError)
+    assert (tr_err.value.errors[0].errors[0].msg ==
+            'This datatype does not accept collections of values (e.g. Lists).')
     rt2rec = db.Record(name="Test_RT2_Rec").add_parent("Test_RT2").add_property(
         name="Test_RT1", datatype=db.LIST("Test_RT1"), value=[rt1rec1]).insert()
-    assert_true(rt2rec.is_valid())
+    assert rt2rec.is_valid()
 
 
 def test_list_in_sub_property():
-    rt1 = db.RecordType(name="TestRT1").insert()
-    rt2 = db.RecordType(name="TestRT2").insert()
-    p = db.Property(name="TestProperty", datatype="TestRT1").insert()
-    p2 = db.Property(name="TestBogusProperty", datatype=db.TEXT).insert()
-    rec1 = db.Record(name="TestRT1Rec1").add_parent("TestRT1").insert()
+    db.RecordType(name="TestRT1").insert()
+    db.RecordType(name="TestRT2").insert()
+    db.Property(name="TestProperty", datatype="TestRT1").insert()
+    db.Property(name="TestBogusProperty", datatype=db.TEXT).insert()
+    db.Record(name="TestRT1Rec1").add_parent("TestRT1").insert()
     rec2 = db.Record(name="TestRT2Rec2").add_parent("TestRT2").add_property(
         "TestProperty", "TestRT1Rec1")
     rec2.get_property("TestProperty").add_property("TestBogusProperty",
diff --git a/tests/test_misc.py b/tests/test_misc.py
index 1d0b6b9ded8854d500cb71481d309801f61c5c67..0da3bffd7b48cd7840ee106954489befe210eb15 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -27,12 +27,13 @@
 @author: tf
 """
 from nose.tools import (assert_equal, assert_is_not_none,  # @UnresolvedImport
-                        assert_not_equal, assert_raises, assert_true, nottest,
+                        assert_not_equal, assert_true, nottest,
                         with_setup)
 
 import caosdb as db
 from caosdb import (Container, Info, Property, Record, RecordType,
                     execute_query)
+from pytest import raises
 
 
 def setup():
@@ -142,16 +143,18 @@ def test_error_no_such_role():
     xml = "<Insert><Entity name='test'/></Insert>"
     r = db.get_connection().insert(entity_uri_segment=["Entity"], body=xml)
     c = Container._response_to_entities(r)
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         db.raise_errors(c)
-    assert_equal(cm.exception.msg, "There is no such role 'Entity'.")
+    assert (cm.value.errors[0].msg ==
+            "There is no such role 'Entity'.")
 
     xml = "<Insert><ASDF name='test'/></Insert>"
     r = db.get_connection().insert(entity_uri_segment=["Entity"], body=xml)
     c = Container._response_to_entities(r)
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         db.raise_errors(c)
-    assert_equal(cm.exception.msg, "There is no such role 'ASDF'.")
+    assert (cm.value.errors[0].msg ==
+            "There is no such role 'ASDF'.")
 
 
 @with_setup(setup, setup)
@@ -181,22 +184,21 @@ def test_parent_duplicate_2():
         inheritance=db.ALL).add_parent(
             name="TestRT1",
         inheritance=db.NONE)
-    assert_equal(len(rt2.get_parents()), 2)
-    with assert_raises(db.TransactionError) as cm:
+    assert len(rt2.get_parents()) == 2
+    with raises(db.TransactionError) as cm:
         rt2.insert()
-    assert_equal(
-        cm.exception.msg,
-        "This entity had parent duplicates. Parent duplicates are meaningless and would be ignored (and inserted only once). But these parents had diverging inheritance instructions which cannot be processed.")
+    assert (cm.value.errors[0].msg ==
+            "This entity had parent duplicates. Parent duplicates are meaningless and would be ignored (and inserted only once). But these parents had diverging inheritance instructions which cannot be processed.")
 
 
 def test_server_error():
     con = db.get_connection()
     con._login()
-    with assert_raises(db.ServerErrorException) as cm:
+    with raises(db.HTTPServerError) as cm:
         con._http_request(
             method="GET",
             path="Entity?debug=throwNullPointerException")
-    assert_true("SRID = " in cm.exception.msg)
+    assert_true("SRID = " in cm.value.msg)
 
 
 def test_annotation():
diff --git a/tests/test_name_properties.py b/tests/test_name_properties.py
index d7f9a56908b7ee259c5972f4bd41168e6d1e2010..028592b7c0a728587f9939e427eb40ba74b9be43 100644
--- a/tests/test_name_properties.py
+++ b/tests/test_name_properties.py
@@ -221,8 +221,8 @@ def test_query_name_property():
 
     assert db.execute_query("FIND TestPerson WITH TestGivenName='John'",
                             unique=True).id == rec.id
-    with raises(db.EntityDoesNotExistError):
-        assert db.execute_query("FIND John", unique=True)
+    with raises(db.BadQueryError):
+        db.execute_query("FIND John", unique=True)
 
     teardown()
 
diff --git a/tests/test_permissions.py b/tests/test_permissions.py
index 3528a63eb8a16bc28938ae4b4d0074cc241f89f0..1953b388a7d87629f9695332c83b2484c7c3cb4b 100644
--- a/tests/test_permissions.py
+++ b/tests/test_permissions.py
@@ -29,13 +29,14 @@
 from __future__ import absolute_import
 
 import caosdb as db
-from nose.tools import (assert_true, assert_equal, assert_raises, assert_false,
-                        assert_is_none, assert_is_not_none, nottest,
-                        with_setup)  # @UnresolvedImport
+from nose.tools import (assert_true,
+                        assert_equal,
+                        assert_raises,
+                        assert_false,
+                        assert_is_none,
+                        assert_is_not_none,
+                        nottest)
 from pytest import raises
-from nose.tools import (assert_equal, assert_false,  # @UnresolvedImport
-                        assert_is_none, assert_is_not_none, assert_raises,
-                        assert_true, nottest, with_setup)
 
 from .test_misc import test_info
 
@@ -116,7 +117,7 @@ def insert_test_user():
     except BaseException:
         pass
 
-    with assert_raises(db.ClientErrorException) as cee:
+    with assert_raises(db.HTTPClientError) as cee:
         db.administration._insert_user(
             name=test_user,
             password=easy_pw,
@@ -160,7 +161,6 @@ def setup():
     test_info()
 
 
-@with_setup(setup, teardown)
 def test_basic_acl_stuff():
     p = db.Property(
         name="TestProperty",
@@ -196,7 +196,6 @@ def test_basic_acl_stuff():
     assert_false("DELETE" in other_role_permissions)
 
 
-@with_setup(setup, teardown)
 def test_query():
     person = db.RecordType("TestPerson").insert()
     db.Property("TestFirstName", datatype=db.TEXT).insert()
@@ -211,30 +210,21 @@ def test_query():
         name="TestConductor",
         value=dan.id).insert()
 
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment WHICH HAS A TestConductor->TestPerson",
-            unique=True).id,
-        exp.id)
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment WHICH HAS A TestConductor=TestPerson",
-            unique=True).id,
-        exp.id)
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment WHICH HAS A TestConductor=" + str(dan.id),
-            unique=True).id, exp.id)
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment",
-            unique=True).id,
-        exp.id)
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment WHICH HAS A TestConductor WHICH has a TestFirstName=Daniel",
-            unique=True).id,
-        exp.id)
+    assert db.execute_query(
+        "FIND TestExperiment WHICH HAS A TestConductor->TestPerson",
+        unique=True).id == exp.id
+    assert db.execute_query(
+        "FIND TestExperiment WHICH HAS A TestConductor=TestPerson",
+        unique=True).id == exp.id
+    assert db.execute_query(
+        "FIND TestExperiment WHICH HAS A TestConductor=" + str(dan.id),
+        unique=True).id == exp.id
+    assert db.execute_query(
+        "FIND TestExperiment",
+        unique=True).id == exp.id
+    assert db.execute_query(
+        "FIND TestExperiment WHICH HAS A TestConductor WHICH has a TestFirstName=Daniel",
+        unique=True).id == exp.id
 
     '''success'''
     grant_permission(person, "RETRIEVE:*")
@@ -242,11 +232,9 @@ def test_query():
     grant_permission(exp, "RETRIEVE:*")
 
     switch_to_test_user()
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment WHICH HAS A TestConductor WHICH has a TestFirstName=Daniel",
-            unique=True).id,
-        exp.id)
+    assert db.execute_query(
+        "FIND TestExperiment WHICH HAS A TestConductor WHICH has a TestFirstName=Daniel",
+        unique=True).id == exp.id
 
     '''failure - dan'''
     deny_permission(dan, "RETRIEVE:*")
@@ -254,40 +242,31 @@ def test_query():
 
     # this fails if server is configured with
     # QUERY_FILTER_ENTITIES_WITHOUT_RETRIEVE_PERMISSIONS = FALSE
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.EmptyUniqueQueryError):
         db.execute_query(
             "FIND TestExperiment WHICH HAS A TestConductor WHICH has a TestFirstName=Daniel",
             unique=True)
-    assert_equal(cm.exception.msg, "No such entity found.")
     '''... but works without the which clause'''
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment",
-            unique=True).id,
-        exp.id)
+    assert db.execute_query("FIND TestExperiment", unique=True).id == exp.id
     '''and with the id'''
-    assert_equal(
-        db.execute_query(
-            "FIND TestExperiment WHICH HAS A TestConductor=" + str(dan.id),
-            unique=True).id, exp.id)
+    assert db.execute_query(
+        "FIND TestExperiment WHICH HAS A TestConductor=" + str(dan.id),
+        unique=True).id == exp.id
 
     '''failure - exp'''
     grant_permission(dan, "RETRIEVE:*")
     deny_permission(exp, "RETRIEVE:*")
     switch_to_test_user()
 
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.EmptyUniqueQueryError):
         db.execute_query(
             "FIND TestExperiment WHICH HAS A TestConductor=TestDaniel",
             unique=True)
-    assert_equal(cm.exception.msg, "No such entity found.")
 
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.EmptyUniqueQueryError):
         db.execute_query("FIND TestExperiment", unique=True)
-    assert_equal(cm.exception.msg, "No such entity found.")
 
 
-@with_setup(setup, teardown)
 def test_update_acl():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
     assert_true(p.is_valid())
@@ -363,40 +342,32 @@ def test_update_acl():
     p3.acl.deny(
         username=db.get_config().get("Connection", "username"),
         permission="USE:AS_PROPERTY")
-    try:
+    with raises(db.TransactionError) as te:
         p3.update_acl()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     p3 = db.execute_query(
         "FIND TestProperty",
         unique=True,
         flags={
             "ACL": None})
-    assert_true(p3.is_valid())
-    assert_is_not_none(p3.acl)
-    assert_true(
-        "USE:AS_PROPERTY" in p3.acl.get_permissions_for_user(
-            db.get_config().get("Connection", "username")))
-    assert_false(
-        "USE:AS_DATA_TYPE" in p3.acl.get_permissions_for_user(
-            db.get_config().get("Connection", "username")))
-    assert_false(
-        "EDIT:ACL" in p3.acl.get_permissions_for_user(
+    assert p3.is_valid()
+    assert p3.acl is not None
+    assert ("USE:AS_PROPERTY" in p3.acl.get_permissions_for_user(
             db.get_config().get("Connection", "username")))
+    assert not ("USE:AS_DATA_TYPE" in p3.acl.get_permissions_for_user(
+        db.get_config().get("Connection", "username")))
+    assert not ("EDIT:ACL" in p3.acl.get_permissions_for_user(
+        db.get_config().get("Connection", "username")))
 
     '''Failure'''
     switch_to_test_user()
     p3.acl.grant(username=test_user, permission="EDIT:ACL")
-    try:
+    with raises(db.TransactionError) as te:
         p3.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
 
-@with_setup(setup, teardown)
 def test_update_name():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
     assert_true(p.is_valid())
@@ -420,18 +391,15 @@ def test_update_name():
     assert_false("UPDATE:NAME" in p.permissions)
 
     p.name = "TestPropertyEvenNewer"
-    try:
+    with raises(db.TransactionError) as te:
         p.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     p2 = db.execute_query("FIND Test*", unique=True)
-    assert_true(p2.is_valid())
-    assert_equal(p2.name, "TestPropertyNew")
+    assert p2.is_valid()
+    assert p2.name == "TestPropertyNew"
 
 
-@with_setup(setup, teardown)
 def test_update_desc():
     p = db.Property(
         name="TestProperty",
@@ -456,18 +424,15 @@ def test_update_desc():
 
     '''Failure'''
     p.description = "DescriptionEvenNewer"
-    try:
+    with raises(db.TransactionError) as te:
         p.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     p2 = db.execute_query("FIND Test*", unique=True)
-    assert_true(p2.is_valid())
-    assert_equal(p2.description, "DescriptionNew")
+    assert p2.is_valid()
+    assert p2.description == "DescriptionNew"
 
 
-@with_setup(setup, teardown)
 def test_update_data_type():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
     assert_true(p.is_valid())
@@ -488,18 +453,15 @@ def test_update_data_type():
 
     '''Failure'''
     p.datatype = db.DOUBLE
-    try:
+    with raises(db.TransactionError) as te:
         p.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     p2 = db.execute_query("FIND Test*", unique=True)
-    assert_true(p2.is_valid())
-    assert_equal(p2.datatype, db.INTEGER)
+    assert p2.is_valid()
+    assert p2.datatype == db.INTEGER
 
 
-@with_setup(setup, teardown)
 def test_update_role():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
     assert_true(p.is_valid())
@@ -518,18 +480,15 @@ def test_update_role():
 
     '''Failure'''
     rec = db.Record(name="TestProperty").retrieve()
-    try:
+    with raises(db.TransactionError) as te:
         rec.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt2 = db.execute_query("FIND Test*", unique=True)
-    assert_true(rt2.is_valid())
-    assert_true(isinstance(rt2, db.RecordType))
+    assert rt2.is_valid()
+    assert isinstance(rt2, db.RecordType)
 
 
-@with_setup(setup, teardown)
 def test_update_move_file():
     upload_file = open("test.dat", "w")
     upload_file.write("hello world\n")
@@ -555,38 +514,33 @@ def test_update_move_file():
 
     '''FAILURE'''
     f.path = "/againotherpermissiontestfiles/test.dat"
-    try:
+    with raises(db.TransactionError) as te:
         f.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     f2 = db.execute_query("FIND TestFile", unique=True)
-    assert_equal(f2.path, "/otherpermissiontestfiles/test.dat")
+    assert f2.path == "/otherpermissiontestfiles/test.dat"
 
 
-@with_setup(setup, teardown)
 def test_update_add_file():
     upload_file = open("test.dat", "w")
     upload_file.write("test update add file: #here#\n")
     upload_file.close()
 
     f = db.File(name="TestFile").insert()
-    assert_true(f.is_valid())
+    assert f.is_valid()
 
     grant_permission(f, "RETRIEVE:ENTITY")
     '''FAILURE'''
 
     f.path = "/permissiontestfiles/newtest.dat"
     f.file = upload_file
-    try:
+    with raises(db.TransactionError) as te:
         f.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     f2 = db.execute_query("FIND TestFile", unique=True)
-    assert_is_none(f2.path)
+    assert f2.path is None
 
     '''SUCCESS'''
     grant_permission(f, "UPDATE:FILE:ADD")
@@ -601,7 +555,6 @@ def test_update_add_file():
     assert_equal(f2.path, "/permissiontestfiles/newtest.dat")
 
 
-@with_setup(setup, teardown)
 def test_update_change_file():
     upload_file = open("test.dat", "w")
     upload_file.write("hello world\n")
@@ -623,16 +576,14 @@ def test_update_change_file():
     deny_permission(f, "UPDATE:FILE:REMOVE")
 
     f.file = upload_file2
-    try:
+    with raises(db.TransactionError) as te:
         f.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     f2 = db.execute_query("FIND TestFile", unique=True)
     download_file = f2.download()
-    assert_equal(db.File._get_checksum(download_file),
-                 db.File._get_checksum(upload_file))
+    assert db.File._get_checksum(
+        download_file) == db.File._get_checksum(upload_file)
 
     '''SUCCESS'''
     print('#################################################################')
@@ -646,15 +597,14 @@ def test_update_change_file():
     f2 = db.execute_query("FIND TestFile", unique=True)
     f2.file = upload_file2
     f2.update()
-    assert_true(f2.is_valid())
+    assert f2.is_valid()
 
     f2 = db.execute_query("FIND TestFile", unique=True)
     download_file = f2.download()
-    assert_equal(db.File._get_checksum(download_file),
-                 db.File._get_checksum(upload_file2))
+    assert db.File._get_checksum(
+        download_file) == db.File._get_checksum(upload_file2)
 
 
-@with_setup(setup, teardown)
 def test_update_add_property():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
     assert_true(p.is_valid())
@@ -685,30 +635,25 @@ def test_update_add_property():
 
     '''Failure - add p to rt'''
     rt.add_property(name="TestProperty", id=p.id)
-    try:
+    with raises(db.TransactionError) as te:
         rt.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt2 = db.execute_query("FIND TestRecordType", unique=True)
-    assert_equal(len(rt2.get_properties()), 1)
-    assert_is_not_none(rt2.get_property("TestProperty"))
+    assert len(rt2.get_properties()) == 1
+    assert rt2.get_property("TestProperty") is not None
 
     '''Failure - add p2 to rt'''
     rt.add_property(name="TestProperty2", id=p2.id)
-    try:
+    with raises(db.TransactionError) as te:
         rt.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt2 = db.execute_query("FIND TestRecordType", unique=True)
-    assert_equal(len(rt2.get_properties()), 1)
-    assert_is_not_none(rt2.get_property("TestProperty"))
+    assert len(rt2.get_properties()) == 1
+    assert rt2.get_property("TestProperty") is not None
 
 
-@with_setup(setup, teardown)
 def test_update_remove_property():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
     assert_true(p.is_valid())
@@ -745,18 +690,15 @@ def test_update_remove_property():
 
     '''Failure - remove p from rt'''
     rt.remove_property("TestProperty")
-    try:
+    with raises(db.TransactionError) as te:
         rt.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt2 = db.execute_query("FIND TestRecordType", unique=True)
-    assert_equal(len(rt2.get_properties()), 1)
-    assert_is_not_none(rt2.get_property("TestProperty"))
+    assert len(rt2.get_properties()) == 1
+    assert rt2.get_property("TestProperty") is not None
 
 
-@with_setup(setup, teardown)
 def test_update_add_parent():
     rt = db.RecordType(name="TestRecordType").insert()
     assert_true(rt.is_valid())
@@ -786,31 +728,26 @@ def test_update_add_parent():
 
     '''Failure - add par1 to rt'''
     rt.add_parent(name="TestRecordTypePar1", id=par1.id)
-    try:
+    with raises(db.TransactionError) as te:
         rt.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt2 = db.execute_query("FIND TestRecordType", unique=True)
-    assert_equal(len(rt2.get_parents()), 1)
-    assert_is_not_none(rt2.get_parent("TestRecordTypePar1"))
+    assert len(rt2.get_parents()) == 1
+    assert rt2.get_parent("TestRecordTypePar1") is not None
 
     '''Failure - add par2 to rt'''
     rt.add_parent(name="TestRecordTypePar2", id=par2.id)
-    try:
+    with raises(db.TransactionError) as te:
         rt.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt2 = db.execute_query("FIND TestRecordType", unique=True)
-    assert_equal(len(rt2.get_parents()), 1)
-    assert_is_not_none(rt2.get_parent("TestRecordTypePar1"))
-    assert_is_none(rt2.get_parent("TestRecordTypePar2"))
+    assert len(rt2.get_parents()) == 1
+    assert rt2.get_parent("TestRecordTypePar1") is not None
+    assert rt2.get_parent("TestRecordTypePar2") is None
 
 
-@with_setup(setup, teardown)
 def test_update_remove_parent():
     par1 = db.RecordType(name="TestRecordTypePar1").insert()
     assert_true(par1.is_valid())
@@ -844,29 +781,26 @@ def test_update_remove_parent():
 
     '''Failure'''
     rt.remove_parent("TestRecordTypePar1")
-    try:
+    with raises(db.TransactionError) as te:
         rt.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     rt = db.execute_query("FIND TestRecordType", unique=True)
-    assert_equal(len(rt.get_parents()), 1)
-    assert_is_not_none(rt.get_parent("TestRecordTypePar1"))
-    assert_is_none(rt.get_parent("TestRecordTypePar2"))
+    assert len(rt.get_parents()) == 1
+    assert rt.get_parent("TestRecordTypePar1") is not None
+    assert rt.get_parent("TestRecordTypePar2") is None
 
 
-@with_setup(setup, teardown)
 def test_update_value():
     p = db.Property(
         name="TestProperty",
         datatype=db.TEXT,
         value="Value").insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
 
     p = db.execute_query("FIND Test*", unique=True)
-    assert_true(p.is_valid())
-    assert_equal(p.value, "Value")
+    assert p.is_valid()
+    assert p.value == "Value"
 
     grant_permission(p, "RETRIEVE:ENTITY")
     grant_permission(p, "UPDATE:VALUE")
@@ -876,53 +810,47 @@ def test_update_value():
     p.update()
 
     p = db.execute_query("FIND Test*", unique=True)
-    assert_true(p.is_valid())
-    assert_equal(p.value, "NewValue")
+    assert p.is_valid()
+    assert p.value == "NewValue"
 
     deny_permission(p, "UPDATE:VALUE")
 
     '''Failure'''
     p.value = "EvenNewerValue"
-    try:
+    with raises(db.TransactionError) as te:
         p.update()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     p2 = db.execute_query("FIND Test*", unique=True)
-    assert_true(p2.is_valid())
-    assert_equal(p2.value, "NewValue")
+    assert p2.is_valid()
+    assert p2.value == "NewValue"
 
 
-@with_setup(setup, teardown)
 def test_deletion():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
 
     grant_permission(p, "RETRIEVE:ENTITY")
     '''Failure'''
 
     p = db.execute_query("FIND Test*", unique=True)
-    assert_true(p.is_valid())
-    try:
+    assert p.is_valid()
+    with raises(db.TransactionError) as te:
         p.delete()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     '''Success'''
     grant_permission(p, "DELETE")
 
+    print(p)
     p.delete()
-    assert_equal(
-        p.get_messages()[0].description,
-        "This entity has been deleted successfully.")
+    assert p.get_messages()[
+        0].description == "This entity has been deleted successfully."
 
 
-@with_setup(setup, teardown)
 def test_retrieve_acl():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
 
     '''Success'''
     grant_permission(p, "RETRIEVE:*")
@@ -931,16 +859,14 @@ def test_retrieve_acl():
     '''Failure'''
     deny_permission(p, "RETRIEVE:ACL")
 
-    try:
+    with raises(db.TransactionError) as te:
         p.retrieve_acl()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
 
 def test_retrieve_history():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
 
     grant_permission(p, "RETRIEVE:ENTITY")
     p.retrieve()
@@ -948,9 +874,9 @@ def test_retrieve_history():
     assert p.version.username is None, "username belongs to history"
 
     '''Failure'''
-    with raises(db.TransactionError) as exc:
+    with raises(db.TransactionError) as te:
         p.retrieve(flags={"H": None})
-    assert "You are not allowed to do this." in str(exc.value)
+    assert te.value.has_error(db.AuthorizationError)
 
     '''Success'''
     grant_permission(p, "RETRIEVE:HISTORY")
@@ -960,11 +886,10 @@ def test_retrieve_history():
     assert p.version.username == db.get_config().get("Connection", "username")
 
 
-@with_setup(setup, teardown)
 def test_retrieve_entity():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
 
-    assert_true(p.is_valid())
+    assert p.is_valid()
 
     ''' Success'''
     grant_permission(p, "RETRIEVE:*")
@@ -973,27 +898,22 @@ def test_retrieve_entity():
     '''Failure'''
     deny_permission(p, "RETRIEVE:ENTITY")
 
-    try:
+    with raises(db.TransactionError) as te:
         p.retrieve()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
 
-@with_setup(setup, teardown)
 def test_retrieve_owner():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
 
     '''Failure'''
     grant_permission(p, "RETRIEVE:ENTITY")
     deny_permission(p, "RETRIEVE:OWNER")
 
-    try:
+    with raises(db.TransactionError) as te:
         p.retrieve(flags={"owner": None})
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, "You are not allowed to do this.")
+    assert te.value.has_error(db.AuthorizationError)
 
     '''Success'''
     grant_permission(p, "RETRIEVE:OWNER")
@@ -1001,7 +921,6 @@ def test_retrieve_owner():
     p.retrieve(flags={"owner": None})
 
 
-@with_setup(setup, teardown)
 def test_download_file():
     upload_file = open("test.dat", "w")
     upload_file.write("hello world\n")
@@ -1011,7 +930,7 @@ def test_download_file():
         name="TestFile",
         file=upload_file,
         path="permissiontestfiles/test.dat").insert()
-    assert_true(f.is_valid())
+    assert f.is_valid()
 
     '''FAILURE'''
     f2 = db.execute_query("FIND TestFile", unique=True)
@@ -1019,81 +938,65 @@ def test_download_file():
     grant_permission(f2, "RETRIEVE:ENTITY")
     deny_permission(f2, "RETRIEVE:FILE")
 
-    try:
+    with raises(db.HTTPForbiddenError):
         f.download()
-    except db.TransactionError as e:
-        assert_equal(
-            e.msg,
-            "Request failed. The response returned with status 403.")
 
     '''SUCCESS'''
     grant_permission(f2, "RETRIEVE:FILE")
 
     f2 = db.execute_query("FIND TestFile", unique=True)
     download_file = f2.download()
-    assert_equal(db.File._get_checksum(download_file),
-                 db.File._get_checksum(upload_file))
+    assert db.File._get_checksum(
+        download_file) == db.File._get_checksum(upload_file)
 
 
-@with_setup(setup, teardown)
 def test_grant_priority_permission():
     p = db.Property(name="TestProperty2", datatype=db.TEXT).insert()
 
     switch_to_test_user()
-    try:
+    with raises(db.TransactionError) as te:
         # other user cannot delete this.
         p.delete()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, 'You are not allowed to do this.')
+    assert te.value.has_error(db.AuthorizationError)
 
     deny_permission(p, "DELETE")
 
-    try:
+    with raises(db.TransactionError) as te:
         # still not working
         p.delete()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, 'You are not allowed to do this.')
+    assert te.value.has_error(db.AuthorizationError)
 
     # now its working
     grant_permission(p, "DELETE", priority=True)
     p.delete()
 
 
-@with_setup(setup, teardown)
 def test_deny_priority_permission():
     p = db.Property(name="TestProperty1", datatype=db.TEXT).insert()
 
     switch_to_test_user()
-    try:
+    with raises(db.TransactionError) as te:
         # other user cannot delete this.
         p.delete()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, 'You are not allowed to do this.')
+    assert te.value.has_error(db.AuthorizationError)
 
     deny_permission(p, "DELETE")
 
-    try:
+    with raises(db.TransactionError) as te:
         # still not working
         p.delete()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, 'You are not allowed to do this.')
+    assert te.value.has_error(db.AuthorizationError)
 
-    # now its working
+    # now it's working
     grant_permission(p, "DELETE")
+    # now it's not
     deny_permission(p, "DELETE", priority=True)
-    try:
+    with raises(db.TransactionError) as te:
         # still not working
         p.delete()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, 'You are not allowed to do this.')
+    assert te.value.has_error(db.AuthorizationError)
 
 
-@with_setup(setup, teardown)
 def test_change_priority_permission():
     entity = db.Property(name="TestProperty1", datatype=db.TEXT).insert()
     grant_permission(entity, "*")
@@ -1105,14 +1008,11 @@ def test_change_priority_permission():
         permission="USE:AS_PROPERTY",
         priority=True)
 
-    try:
+    with raises(db.TransactionError) as te:
         entity.update_acl()
-        assert_true(False)
-    except db.TransactionError as e:
-        assert_equal(e.msg, 'You are not allowed to do this.')
+    assert te.value.has_error(db.AuthorizationError)
 
 
-@with_setup(setup, teardown)
 def test_permissions_there():
     entity = db.Property(name="TestProperty1", datatype=db.TEXT).insert()
     assert_is_not_none(entity.permissions)
@@ -1123,15 +1023,14 @@ def test_permissions_there():
     assert_true(entity2.is_permitted("RETRIEVE:ACL"))
 
 
-@with_setup(setup, teardown)
 def test_grant_nonsense_permission():
     entity = db.Property(name="TestProperty1", datatype=db.TEXT).insert()
     entity.retrieve_acl()
     entity.grant(username="someone", permission="PAINT:BLUE")
-    assert_raises(db.TransactionError, entity.update_acl)
+    with raises(db.TransactionError):
+        entity.update_acl()
 
 
-@with_setup(setup, teardown)
 def test_global_acl_there():
     assert_is_not_none(db.get_global_acl())
     assert_true(isinstance(db.get_global_acl(), db.ACL))
@@ -1141,31 +1040,28 @@ def test_global_acl_there():
     print(db.get_global_acl())
 
 
-@with_setup(setup, teardown)
 def test_use_as_property():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
     switch_to_test_user()
     rt = db.RecordType(name="TestRecordType").add_property(name="TestProperty")
 
     deny_permission(p, "USE:AS_PROPERTY")
     '''Failure'''
     deny_permission(p, "USE:AS_PROPERTY")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         rt.insert()
-    ex = cm.exception
-    assert_equal(ex.msg, "Entity has unqualified properties.")
-    assert_equal(rt.get_property("TestProperty").get_errors()[0].code, "403")
+    assert cm.value.has_error(db.UnqualifiedPropertiesError)
+    assert int(rt.get_property("TestProperty").get_errors()[0].code) == 403
 
     '''Success'''
     grant_permission(p, "USE:AS_PROPERTY")
     rt2 = db.RecordType(
         name="TestRecordType").add_property(
         name="TestProperty").insert()
-    assert_true(rt2.is_valid())
+    assert rt2.is_valid()
 
 
-@with_setup(setup, teardown)
 def test_use_as_data_type():
     dt_name = "TestPersonRecordType"
     dt = db.RecordType(name=dt_name).insert()
@@ -1176,12 +1072,11 @@ def test_use_as_data_type():
     db.Property(name="TestConductorProperty", datatype=dt_name).insert()
 
     deny_permission(dt, "USE:AS_DATA_TYPE")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         db.Property(name="TestConductorProperty2", datatype=dt_name).insert()
-    assert_equal(cm.exception.msg, "You are not allowed to do this.")
+    assert cm.value.has_error(db.AuthorizationError)
 
 
-@with_setup(setup, teardown)
 def test_use_as_reference():
 
     p = db.RecordType(name="TestRecordTypeForReference").insert()
@@ -1196,23 +1091,22 @@ def test_use_as_reference():
         name="TestRecordType").add_property(
         name="TestRecordTypeForReference",
         value=rec).insert()
-    assert_true(rt.is_valid())
+    assert rt.is_valid()
 
     deny_permission(rec, "USE:AS_REFERENCE")
     rt2 = db.RecordType(
         name="TestRecordType2").add_property(
         name="TestRecordTypeForReference",
         value=rec)
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         rt2.insert()
-    assert_equal(cm.exception.msg, "Entity has unqualified properties.")
-    assert_equal(rt2.get_property(p.name).get_errors()[0].code, "403")
+    assert cm.value.has_error(db.UnqualifiedPropertiesError)
+    assert int(rt2.get_property(p.name).get_errors()[0].code) == 403
 
 
-@with_setup(setup, teardown)
 def test_use_as_parent():
     p = db.Property(name="TestProperty", datatype=db.TEXT).insert()
-    assert_true(p.is_valid())
+    assert p.is_valid()
     switch_to_test_user()
 
     p2 = db.Property(
@@ -1223,20 +1117,19 @@ def test_use_as_parent():
     deny_permission(p, "USE:AS_PARENT")
     '''Failure'''
     deny_permission(p, "USE:AS_PARENT")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         p2.insert()
-    assert_equal(cm.exception.msg, "Entity has unqualified parents.")
-    assert_equal(p2.get_parent("TestProperty").get_errors()[0].code, "403")
+    assert cm.value.has_error(db.UnqualifiedParentsError)
+    assert int(p2.get_parent("TestProperty").get_errors()[0].code) == 403
 
     '''Success'''
     grant_permission(p, "USE:AS_PARENT")
     p3 = db.Property(
         name="TestPropertyChild").add_parent(
         name="TestProperty").insert()
-    assert_true(p3.is_valid())
+    assert p3.is_valid()
 
 
-@with_setup(setup, teardown)
 def test_access_control_job_bug():
     """test_access_control_job_bug.
 
@@ -1247,12 +1140,12 @@ def test_access_control_job_bug():
     """
     revoke_permissions_test_role()
     switch_to_test_user()
-    with raises(db.AuthorizationException):
+    with raises(db.TransactionError) as te:
         rt1 = db.RecordType(name="TestRT").add_parent(id=-5).insert()
+    assert te.value.has_error(db.AuthorizationError)
     set_transaction_permissions_test_role()
 
 
-@with_setup(setup, teardown)
 def test_check_entity_acl_roles():
     '''Test the CheckEntityACLRoles class.
 
@@ -1277,7 +1170,7 @@ def test_check_entity_acl_roles():
     with raises(db.TransactionError) as cm:
         grant_permission(p, "USE:AS_PARENT", username="asdf-non-existing",
                          switch=False)
-    errors = cm.value.entity.get_errors()
+    errors = cm.value.entities[0].get_errors()
     assert errors[0].description == "User Role does not exist."
     db.administration.set_server_property(
         "CHECK_ENTITY_ACL_ROLES_MODE", "SHOULD")
diff --git a/tests/test_query.py b/tests/test_query.py
index 8432b37d92c87d772ff07c0b4772def48b6aaab1..eccd303cccb3370ceba1fc6a48c98017a43789a6 100644
--- a/tests/test_query.py
+++ b/tests/test_query.py
@@ -27,6 +27,8 @@
 """
 
 
+import os
+import random
 import caosdb as h
 
 from pytest import mark
@@ -35,6 +37,10 @@ from caosdb.connection.connection import get_connection
 from lxml import etree
 
 
+def setup_module():
+    h.administration.set_server_property("AUTH_OPTIONAL", "TRUE")
+
+
 def setup():
     try:
         h.execute_query("FIND Test*").delete()
@@ -43,9 +49,9 @@ def setup():
 
 
 def teardown():
+    h.configure_connection()
     setup()
     try:
-        import os
         os.remove("test.dat")
     except Exception as e:
         print(e)
@@ -202,6 +208,7 @@ def test_query3():
     assert_equal(3, len(xml))
 
 
+@mark.slow
 def test_conjunction():
     rt = h.RecordType(name="TestConjunctionTest").insert()
     assert_true(rt.is_valid())
@@ -292,6 +299,7 @@ def test_conjunction():
         "FIND RECORD . TestConjunctionTestPropertyA=1 AND TestConjunctionTestPropertyB=0")))
 
 
+@mark.slow
 def test_disjunction():
     rt = h.RecordType(name="TestDisjunctionTest").insert()
     assert_true(rt.is_valid())
@@ -376,6 +384,7 @@ def test_disjunction():
         "FIND TestDisjunctionTest . TestDisjunctionTestPropertyA=1 OR ( TestDisjunctionTestPropertyB=0 AND TestDisjunctionTestPropertyA=1)")))
 
 
+@mark.slow
 def test_greatest():
     pAB = h.Property(name="TestPropertyAB", datatype=h.DOUBLE).insert()
     assert_true(pAB.is_valid())
@@ -636,40 +645,49 @@ def test_wildcard_values():
     assert_equal(0, len(c))
 
 
+def store_file(path, name=None, f=None):
+    """insert a file for testing purposes."""
+    tmp_file = None
+    if f is None:
+        tmp_file = open("test.dat", "w")
+        tmp_file.write("hello world\n")
+        tmp_file.close()
+        f = tmp_file
+    if name is None:
+        name = "TestFile%030x" % random.randrange(16**30)
+
+    file_ = h.File(name=name,
+                   description="Testfile Desc",
+                   path=path,
+                   file="test.dat")
+    file_.insert()
+
+    if tmp_file is not None:
+        os.remove("test.dat")
+    return file_
+
+
 def test_stored_at_wildcards():
 
     upload_file = open("test.dat", "w")
     upload_file.write("hello world\n")
     upload_file.close()
 
-    global i
-    i = 1
+    file1 = store_file("test1.dat", f=upload_file)
 
-    def store_file(path):
-        global i
-        file_ = h.File(name="TestTestFile" + str(i),
-                       description="Testfile Desc",
-                       path=path,
-                       file="test.dat")
-        i += 1
-        file_.insert()
-        return file_
+    file2 = store_file("/rootdir/test2.dat", f=upload_file)
 
-    file1 = store_file("test1.dat")
+    file3 = store_file("/rootdir/subdir1/test3.dat", f=upload_file)
 
-    file2 = store_file("/rootdir/test2.dat")
+    file4 = store_file("/rootdir/subdir1/subdir2/test4.dat", f=upload_file)
 
-    file3 = store_file("/rootdir/subdir1/test3.dat")
+    file5 = store_file("test5.dat", f=upload_file)
 
-    file4 = store_file("/rootdir/subdir1/subdir2/test4.dat")
+    file6 = store_file("rootdir/test*6.dat", f=upload_file)
 
-    file5 = store_file("test5.dat")
+    file7 = store_file("rootdir/subdir1/test%7.dat", f=upload_file)
 
-    file6 = store_file("rootdir/test*6.dat")
-
-    file7 = store_file("rootdir/subdir1/test%7.dat")
-
-    file8 = store_file("rootdir/subdir1/test%8.dat")
+    file8 = store_file("rootdir/subdir1/test%8.dat", f=upload_file)
 
     c = h.execute_query("FIND FILE WHICH IS STORED AT /*.dat")
     assert_equal(len(c), 2)
@@ -849,6 +867,7 @@ def test_stored_at_wildcards():
     assert c.get_entity_by_id(file8.id) is not None
 
 
+@mark.slow
 def test_int():
     pint = h.Property(name="TestIntegerProperty", datatype=h.INTEGER).insert()
     pdouble = h.Property(name="TestDoubleProperty", datatype=h.DOUBLE).insert()
@@ -1024,3 +1043,191 @@ def test_referenced_as():
                               "TestParty AS Guests")
     assert len(guests) == 3
     assert set([e.id for e in guests]) == guest_ids
+
+
+def test_query_cache():
+    entity = h.RecordType("TestRT").insert()
+
+    # fill cache
+    query = h.Query("COUNT TestRT")
+    assert query.cached is None
+    response = query.execute()
+    assert response == 1
+    assert query.cached == False
+
+    # cached == True
+    query = h.Query("COUNT TestRT")
+    assert query.cached is None
+    response = query.execute()
+    assert response == 1
+    assert query.cached == True
+
+    # cached == True
+    query = h.Query("FIND TestRT")
+    assert query.cached is None
+    response = query.execute(unique=True)
+    assert response.id == entity.id
+    assert query.cached == True
+
+    # cached == True
+    query = h.Query("SELECT bla FROM TestRT")
+    assert query.cached is None
+    response = query.execute(unique=True)
+    assert response.id == entity.id
+    assert query.cached == True
+
+    # no cache flag
+    query = h.Query("SELECT bla FROM TestRT")
+    assert query.cached is None
+    response = query.execute(unique=True, cache=False)
+    assert response.id == entity.id
+    assert query.cached == False
+
+    # cached == True
+    query = h.Query("SELECT bla FROM TestRT")
+    assert query.cached is None
+    response = query.execute(unique=True)
+    assert response.id == entity.id
+    assert query.cached == True
+
+    # write resets cache
+    another_entity = h.Record().add_parent("TestRT").insert()
+
+    # cached == False
+    query = h.Query("COUNT TestRT")
+    assert query.cached is None
+    response = query.execute()
+    assert response == 2
+    assert query.cached == False
+
+    # cached == True
+    query = h.Query("COUNT TestRT")
+    assert query.cached is None
+    response = query.execute()
+    assert response == 2
+    assert query.cached == True
+
+
+def test_query_cache_with_permissions():
+    h.RecordType("TestRT").insert()
+    h.RecordType("TestRT2").insert()
+    public_record = h.Record().add_parent("TestRT").insert()
+    referenced = h.Record().add_parent("TestRT2").insert()
+    private_record = h.Record().add_parent(
+        "TestRT").add_property("TestRT2",
+                               referenced).insert(flags={"ACL": None})
+
+    # proof: query as anonymous works in principle
+    h.configure_connection(password_method="unauthenticated")
+    query = h.Query("COUNT Record TestRT")
+    response = query.execute()
+    assert response == 2
+    assert query.cached == False
+
+    query = h.Query("COUNT Record WHICH IS REFERENCED BY TestRT")
+    response = query.execute()
+    assert response == 1
+    assert query.cached == False
+
+    # remove permissions for anonymous
+    h.configure_connection()
+    private_record.deny(role="anonymous", permission="RETRIEVE:*")
+    private_record.update_acl()  # note: this clears the cache
+
+    # as authenticated user to fill the cache
+    query = h.Query("COUNT Record TestRT")
+    response = query.execute()
+    assert response == 2
+    assert query.cached == False
+
+    query = h.Query("COUNT Record WHICH IS REFERENCED BY TestRT")
+    response = query.execute()
+    assert response == 1
+    assert query.cached == False
+
+    # as anonymous
+    h.configure_connection(password_method="unauthenticated")
+    query = h.Query("COUNT Record TestRT")
+    response = query.execute()
+    assert response == 1
+    assert query.cached == True
+
+    query = h.Query("COUNT Record WHICH IS REFERENCED BY TestRT")
+    response = query.execute()
+    assert response == 0
+    # Caching was not possible due to complex permissions
+    assert query.cached == False
+
+    # try again as authenticated user
+    h.configure_connection()
+    query = h.Query("COUNT Record TestRT")
+    response = query.execute()
+    assert query.cached == True
+    assert response == 2
+
+    query = h.Query("COUNT Record WHICH IS REFERENCED BY TestRT")
+    response = query.execute()
+    assert response == 1
+    # Caching was not possible due to complex permissions
+    assert query.cached == False
+
+
+def test_find_star():
+    """related: caosdb-server#116"""
+    rt = h.RecordType("TestRT").insert()
+    response = h.execute_query("FIND *")[0]
+    assert response.id == rt.id
+
+
+def test_find_entity():
+    rt = h.RecordType("TestRT").insert()
+    response = h.execute_query("FIND ENTITY")[0]
+    assert response.id == rt.id
+
+
+def test_count_any_version_of_entity():
+    vcount1 = h.execute_query("COUNT ANY VERSION OF ENTITY")
+    ecount1 = h.execute_query("COUNT ENTITY")
+    assert ecount1 == 0
+    assert vcount1 == 0
+
+    rt = h.RecordType("TestRT").insert()
+    vcount2 = h.execute_query("COUNT ANY VERSION OF ENTITY")
+    ecount2 = h.execute_query("COUNT ENTITY")
+    assert vcount2 == vcount1 + 1
+    assert ecount2 == ecount1 + 1
+
+    rt.description = "update"
+    rt.update()
+    vcount3 = h.execute_query("COUNT ANY VERSION OF ENTITY")
+    ecount3 = h.execute_query("COUNT ENTITY")
+    assert vcount3 == vcount2 + 1
+    assert ecount3 == ecount2
+
+
+def test_find_nasty_path():
+    """related: caosdb-server#31"""
+    file_1 = store_file("0in.txt")
+    assert h.execute_query(
+        "FIND FILE WHICH IS STORED AT 0in.txt",
+        unique=True).id == file_1.id
+
+    file_2 = store_file(".asdf.txt")
+    assert h.execute_query(
+        "FIND FILE WHICH IS STORED AT .asdf.txt",
+        unique=True).id == file_2.id
+
+    file_3 = store_file(".WITH")
+    assert h.execute_query(
+        "FIND FILE WHICH IS STORED AT .WITH",
+        unique=True).id == file_3.id
+
+    file_4 = store_file("STORED")
+    assert h.execute_query(
+        "FIND FILE WHICH IS STORED AT STORED",
+        unique=True).id == file_4.id
+
+    file_5 = store_file("STORED AT")  # hehe
+    assert h.execute_query(
+        "FIND FILE WHICH IS STORED AT STORED AT",
+        unique=True).id == file_5.id
diff --git a/tests/test_query_template.py b/tests/test_query_template.py
index e2b1c77a3b815419e45f24ad5b4a2131fdab331a..c5fc3c7858e9b87eff6aca6e6d04a8d3d055b8b3 100644
--- a/tests/test_query_template.py
+++ b/tests/test_query_template.py
@@ -26,9 +26,8 @@
 @author: tf
 """
 import caosdb as db
-from nose.tools import (assert_equal, assert_is_none,  # @UnresolvedImport
-                        assert_is_not_none, assert_raises, assert_true,
-                        nottest, with_setup)
+from nose.tools import assert_true, assert_equal, assert_is_not_none
+from pytest import raises
 
 
 def setup_module():
@@ -91,7 +90,6 @@ def teardown():
         print(e)
 
 
-@with_setup(setup, teardown)
 def test_insertion_success():
     return db.QueryTemplate(
         name="TestQueryTemplate",
@@ -99,63 +97,54 @@ def test_insertion_success():
         query="FIND RECORD Experiment WHICH HAS A animal=Pig").insert()
 
 
-@with_setup(setup, teardown)
 def test_insertion_failure_syntax():
     q = db.QueryTemplate(
         name="TestQueryTemplate",
         description="Find some interesting things with via a simple name.",
         query="SDASDUASIUF")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.insert()
-    print(cm.exception)
-    assert_equal(
-        cm.exception.msg,
-        "An error occured during the parsing of this query. Maybe you use a wrong syntax?")
+    print(cm.value)
+    assert (cm.value.errors[0].msg ==
+            "An error occured during the parsing of this query. Maybe you use a wrong syntax?")
 
 
-@with_setup(setup, teardown)
 def test_insertion_failure_count_query_not_allowed():
     q = db.QueryTemplate(
         name="TestQueryTemplate",
         description="Find some interesting things with via a simple name.",
         query="COUNT something")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.insert()
-    assert_equal(
-        cm.exception.msg,
-        "QueryTemplates may not be defined by 'COUNT...' queries for consistency reasons.")
+    assert (cm.value.errors[0].msg ==
+            "QueryTemplates may not be defined by 'COUNT...' queries for consistency reasons.")
 
 
-@with_setup(setup, teardown)
 def test_insertion_failure_select_query_not_allowed():
     query_def = "SELECT TestAnimal FROM TestExperiment WHICH HAS A TestAnimal = Pig"
     q = db.QueryTemplate(
         name="TestQueryTemplate",
         description="Find some interesting things with via a simple name.",
         query=query_def)
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.insert()
-    assert_equal(
-        cm.exception.msg,
-        "QueryTemplates may not be defined by 'SELECT... FROM...' queries for consistency reasons.")
+    assert (cm.value.errors[0].msg ==
+            "QueryTemplates may not be defined by 'SELECT... FROM...' queries for consistency reasons.")
 
 
-@with_setup(setup, teardown)
 def test_deletion_success():
     eid = test_insertion_success().id
     q = db.QueryTemplate(id=eid).delete()
     assert_true(q.is_deleted())
 
 
-@with_setup(setup, teardown)
 def test_deletion_failure_non_existing():
     q = db.QueryTemplate(id="12342")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.delete()
-    assert_equal(cm.exception.msg, "Entity does not exist.")
+    assert cm.value.has_error(db.EntityDoesNotExistError)
 
 
-@with_setup(setup, teardown)
 def test_retrieve_success():
     test_insertion_success()
     q = db.QueryTemplate(name="TestQueryTemplate").retrieve(sync=False)
@@ -164,71 +153,60 @@ def test_retrieve_success():
     assert_equal(q.query, "FIND RECORD Experiment WHICH HAS A animal=Pig")
 
 
-@with_setup(setup, teardown)
 def test_retrieve_failure_non_existing():
     q = db.QueryTemplate(id="12342")
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.retrieve()
-    assert_equal(cm.exception.msg, "Entity does not exist.")
+    assert cm.value.has_error(db.EntityDoesNotExistError)
 
 
-@with_setup(setup, teardown)
 def test_update_success():
     q = test_insertion_success()
     q.query = "FIND NewStuff"
     q.update()
 
 
-@with_setup(setup, teardown)
 def test_update_failure_syntax():
     q = test_insertion_success()
     q.query = "ashdjfkasjdf"
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.update()
-    assert_equal(
-        cm.exception.msg,
-        "An error occured during the parsing of this query. Maybe you use a wrong syntax?")
+    assert(cm.value.errors[0].msg ==
+           "An error occured during the parsing of this query. Maybe you use a wrong syntax?")
 
 
-@with_setup(setup, teardown)
 def test_update_failure_count_query_not_allowed():
     q = test_insertion_success()
     q.query = "COUNT somethingNew"
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.update()
-    assert_equal(
-        cm.exception.msg,
-        "QueryTemplates may not be defined by 'COUNT...' queries for consistency reasons.")
+    assert (cm.value.errors[0].msg ==
+            "QueryTemplates may not be defined by 'COUNT...' queries for consistency reasons.")
 
 
-@with_setup(setup, teardown)
 def test_update_failure_select_query_not_allowed():
     q = test_insertion_success()
     q.query = "SELECT TestAnimal FROM TestExperiment WHICH HAS A TestAnimal = Pig"
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.update()
-    assert_equal(
-        cm.exception.msg,
-        "QueryTemplates may not be defined by 'SELECT... FROM...' queries for consistency reasons.")
+    assert (cm.value.errors[0].msg ==
+            "QueryTemplates may not be defined by 'SELECT... FROM...' queries for consistency reasons.")
 
 
-@with_setup(setup, teardown)
 def test_update_failure_non_existing():
     q = db.QueryTemplate(id="12342")
     q.query = "FIND NewStuff"
-    with assert_raises(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         q.update()
-    assert_equal(cm.exception.msg, "Entity does not exist.")
+    assert cm.value.has_error(db.EntityDoesNotExistError)
 
 
-@with_setup(setup, teardown)
 def test_retrieve_as_entity_success():
     q = test_insertion_success()
     e = db.Entity(id=q.id).retrieve()
     assert_equal(e.id, q.id)
 
 
-@with_setup(setup, teardown)
 def test_query_simple_find():
     query_def = "FIND TestExperiment WHICH HAS A TestAnimal = Pig"
     r = db.execute_query(query_def, unique=True)
@@ -252,7 +230,6 @@ def test_query_simple_find():
         "TestRecord")
 
 
-@with_setup(setup, teardown)
 def test_query_with_select_in_outer_query():
     query_def = "FIND TestExperiment WHICH HAS A TestAnimal = Pig"
     r = db.execute_query(query_def, unique=True)
@@ -281,7 +258,6 @@ def test_query_with_select_in_outer_query():
     assert_equal(len(r.get_properties()), 1)
 
 
-@with_setup(setup, teardown)
 def test_query_with_other_filters():
     query_def = "FIND TestExperiment WHICH HAS A TestAnimal"
     db.QueryTemplate(name="TestAnimalExperiment", query=query_def).insert()
@@ -295,7 +271,6 @@ def test_query_with_other_filters():
     assert_equal(r.name, "TestRecord")
 
 
-@with_setup(setup, teardown)
 def test_query_simple_find_with_wildcard():
     query_def = "FIND TestExperiment WHICH HAS A TestAnimal = Pig"
     db.QueryTemplate(name="TestAnimalExperiment", query=query_def).insert()
@@ -309,7 +284,6 @@ def test_query_simple_find_with_wildcard():
     assert_equal(r.name, "TestRecord")
 
 
-@with_setup(setup, teardown)
 def test_query_select_from_with_wildcard():
     query_def = "FIND TestExperiment WHICH HAS A TestAnimal = Pig"
     db.QueryTemplate(name="TestAnimalExperiment", query=query_def).insert()
@@ -320,7 +294,6 @@ def test_query_select_from_with_wildcard():
     assert_equal(len(r.get_entity_by_name("TestAnimal").get_properties()), 0)
 
 
-@with_setup(setup, teardown)
 def test_query_without_permission():
     query_def = "FIND TestExperiment WHICH HAS A TestAnimal = Pig"
     qt = db.QueryTemplate(name="TestPigExperiment", query=query_def).insert()
@@ -353,7 +326,6 @@ def test_query_without_permission():
     assert_equal(len(r), 0)
 
 
-@with_setup(setup, teardown)
 def test_query_with_subquery_referenced_by():
     assert_equal(
         db.execute_query(
diff --git a/tests/test_query_version.py b/tests/test_query_version.py
index 0b152ee0f3015c08be7d46f680e1694eaeeaa8ca..860bc68514327a8bbfc90777abac4974344b820f 100644
--- a/tests/test_query_version.py
+++ b/tests/test_query_version.py
@@ -133,6 +133,7 @@ def setup_module():
             TEST_REC_1.id) + "@HEAD").insert()
 
 
+@pytest.mark.slow
 def test_normal_find_record():
     result = query("FIND RECORD TestRecord1")
     assert len(result) == 1
diff --git a/tests/test_select.py b/tests/test_select.py
index 66c3992d1519f101b7b18941924b9bd939fa0066..af2bf3a244e262f65b24becb2bada1137adbaa7a 100644
--- a/tests/test_select.py
+++ b/tests/test_select.py
@@ -41,15 +41,22 @@ def setup_module():
         name="TestPropertyOne", value="v1").add_property(
             name="TestPropertyTwo", value="v2").insert()
     rt_house = db.RecordType("TestHouse", description="TestHouseDesc").insert()
-    db.RecordType("TestWindow").insert()
+    db.RecordType("TestHousePart", description="TestHousePartDesc").insert()
+    db.RecordType("TestWindow").add_parent("TestHousePart").insert()
+    db.RecordType("TestDoor").add_parent("TestHousePart").insert()
     rt_person = db.RecordType("TestPerson",
                               description="TestPersonDesc").insert()
     db.RecordType("TestParty", description="TestPartyDesc").insert()
+    db.Property("TestHouseProperty", datatype=db.TEXT).insert()
     db.Property("TestHeight", description="TestHeightDesc", datatype=db.DOUBLE,
-                unit="ft").insert()
+                unit="ft").add_parent("TestHouseProperty").insert()
     db.Property("TestDate", description="TestDateDesc",
                 datatype=db.DATETIME).insert()
 
+    door = db.Record("Door1",
+                     description="Door1Desc").add_parent("TestDoor")
+    door.add_property("TestHeight", "21.5", unit="ft")
+    door.insert()
     window = db.Record("Window1",
                        description="Window1Desc").add_parent("TestWindow")
     window.add_property("TestHeight", 20.5, unit="ft")
@@ -61,7 +68,9 @@ def setup_module():
     house.description = "A rather large house"
     house.add_parent("TestHouse")
     house.add_property(rt_person, name="TestOwner", value=owner)
-    house.add_property("TestWindow", window).insert()
+    house.add_property("TestWindow", [window], datatype=db.LIST("TestWindow"))
+    house.add_property("TestDoor", door)
+    house.insert()
 
     g1 = db.Record().add_parent("TestPerson").insert()
     g2 = db.Record().add_parent("TestPerson").insert()
@@ -183,33 +192,71 @@ def test_sub2():
 
 
 def test_subref():
-    window = db.execute_query("FIND RECORD TestWindow", unique=True)
-    s = db.execute_query("SELECT name, TestWindow.TestHeight.value, "
-                         "TestWindow.TestHeight.unit FROM RECORD TestHouse")
+    door = db.execute_query("FIND RECORD TestDoor", unique=True)
+    s = db.execute_query("SELECT name, TestDoor.TestHeight.value, "
+                         "TestDoor.TestHeight.unit FROM RECORD TestHouse")
 
     assert len(s) == 1
 
-    row = s.get_property_values("name", "TestWindow")[0]
+    row = s.get_property_values("name", "TestDoor")[0]
     assert row[0] == "Buckingham Palace"
-    assert row[1] == window.id
+    assert row[1] == door.id
 
-    row = s.get_property_values("name", ("TestWindow", "TestHeight"))[0]
+    row = s.get_property_values("name", ("TestDoor", "TestHeight"))[0]
     assert row[0] == "Buckingham Palace"
-    assert row[1] == 20.5
+    assert row[1] == 21.5
 
     row = s.get_property_values(
-        "name", ("TestWindow", "TestHeight", "unit"))[0]
+        "name", ("TestDoor", "TestHeight", "unit"))[0]
     assert row[0] == "Buckingham Palace"
     assert row[1] == "ft"
 
 
+def test_subref_list():
+    window = db.execute_query("FIND RECORD TestWindow", unique=True)
+    s = db.execute_query("SELECT name, TestWindow.TestHeight.value, "
+                         "TestWindow.TestHeight.unit FROM RECORD TestHouse")
+
+    assert len(s) == 1
+
+    row = s.get_property_values("name", "TestWindow")[0]
+    assert row[0] == "Buckingham Palace"
+    assert row[1][0].id == window.id
+
+    # current limitation of get_property_values - no lists
+    # row = s.get_property_values("name", ("TestWindow", "TestHeight"))[0]
+    # assert row[0] == "Buckingham Palace"
+    # assert row[1] == 20.5
+    assert row[1][0].get_property("TestHeight").value == 20.5
+
+    # current limitation of get_property_values - no lists
+    # row = s.get_property_values(
+    # "name", ("TestWindow", "TestHeight", "unit"))[0]
+    # assert row[0] == "Buckingham Palace"
+    # assert row[1] == "ft"
+    assert row[1][0].get_property("TestHeight").unit == "ft"
+
+
 def test_subref_deep():
     p = db.execute_query(
-        "SELECT name, Testdate, location, location.TestWindow.Testheight FROM "
+        "SELECT name, Testdate, location, location.TestDoor.Testheight FROM "
         "RECORD TestParty", unique=True)
     row = p.get_property_values("name", "Testdate",
-                                ("location", "Testwindow", "Testheight"))
-    assert row == ("Diamond Jubilee of Elizabeth II", "2012-02-06", 20.5)
+                                ("location", "Testdoor", "Testheight"))
+    assert row == ("Diamond Jubilee of Elizabeth II", "2012-02-06", 21.5)
+
+
+def test_subref_deep_list():
+    p = db.execute_query(
+        "SELECT name, Testdate, location, location.TestWindow.Testheight FROM "
+        "RECORD TestParty", unique=True)
+
+    # current limitation of get_property_values - no lists
+    # row = p.get_property_values("name", "Testdate",
+    # ("location", "Testwindow", "Testheight"))
+    # assert row == ("Diamond Jubilee of Elizabeth II", "2012-02-06", 20.5)
+    assert p.get_property_values(("location", "TestWindow"))[
+        0][0].get_property("TestHeight").value == 20.5
 
 
 def test_select_list():
@@ -218,6 +265,7 @@ def test_select_list():
     s = db.execute_query("SELECT guests FROM RECORD TestParty", unique=True)
 
     column = s.get_property_values("guests")[0]
+    print(s)
     assert len(column) == len(guests)
 
     for eid in [e.id for e in guests]:
@@ -233,17 +281,35 @@ def test_select_unit():
     column = s.get_property_values("unit")
     assert column == ("ft",)
 
-    s = db.execute_query("SELECT TestWindow.TestHeight.unit FROM "
+    s = db.execute_query("SELECT TestDoor.TestHeight.unit FROM "
                          "RECORD TestHouse", unique=True)
-    column = s.get_property_values(("TestWindow", "TestHeight", "unit"))
+    column = s.get_property_values(("TestDoor", "TestHeight", "unit"))
     assert column == ("ft",)
 
-    s = db.execute_query("SELECT TestHeight.unit.TestWindow FROM "
-                         "RECORD TestWindow", unique=True)
-    column = s.get_property_values(("TestHeight", "unit", "TestWindow"))
+    s = db.execute_query("SELECT TestHeight.unit.TestDoor FROM "
+                         "RECORD TestDoor", unique=True)
+    column = s.get_property_values(("TestHeight", "unit", "TestDoor"))
     assert column == (None,)
 
 
+def test_select_unit_list():
+    s = db.execute_query("SELECT unit FROM RECORD TestHouse", unique=True)
+    column = s.get_property_values("unit")
+    assert column == (None,)
+
+    s = db.execute_query("SELECT unit FROM PROPERTY TestHeight", unique=True)
+    column = s.get_property_values("unit")
+    assert column == ("ft",)
+
+    s = db.execute_query("SELECT TestWindow.TestHeight.unit FROM "
+                         "RECORD TestHouse", unique=True)
+    # current limitation of get_property_values - no lists
+    # column = s.get_property_values(("TestWindow", "TestHeight", "unit"))
+    # assert column == ("ft",)
+    assert s.get_property_values(("TestWindow"))[
+        0][0].get_property("TestHeight").unit == "ft"
+
+
 def test_select_description():
     s = db.execute_query("SELECT description FROM RECORD TestPerson")
     column = s.get_property_values("description")
@@ -260,21 +326,50 @@ def test_select_description():
     assert column == ("A rather large house",)
 
     s = db.execute_query("SELECT TestHeight.description FROM "
-                         "RECORD TestWindow", unique=True)
+                         "RECORD TestDoor", unique=True)
     column = s.get_property_values(("TestHeight", "description"))
     assert column == ('TestHeightDesc',)
 
-    s = db.execute_query("SELECT TestWindow.TestHeight.description FROM "
+    s = db.execute_query("SELECT TestDoor.TestHeight.description FROM "
                          "RECORD TestHouse", unique=True)
-    column = s.get_property_values(("TestWindow", "TestHeight", "description"))
+    column = s.get_property_values(("TestDoor", "TestHeight", "description"))
     assert column == ('TestHeightDesc',)
 
-    s = db.execute_query("SELECT TestHeight.description.TestWindow FROM "
-                         "RECORD TestWindow", unique=True)
-    column = s.get_property_values(("TestHeight", "description", "TestWindow"))
+    s = db.execute_query("SELECT TestHeight.description.TestDoor FROM "
+                         "RECORD TestDoor", unique=True)
+    column = s.get_property_values(("TestHeight", "description", "TestDoor"))
     assert column == (None,)
 
 
+def test_select_description_list():
+    s = db.execute_query("SELECT description FROM RECORD TestPerson")
+    column = s.get_property_values("description")
+    assert column == [(None,), (None,), (None,), (None,)]
+
+    s = db.execute_query("SELECT description"
+                         "FROM RECORD TestHouse", unique=True)
+    column = s.get_property_values(("description"))
+    assert column == ("A rather large house",)
+
+    s = db.execute_query("SELECT location.description"
+                         "FROM RECORD TestParty", unique=True)
+    column = s.get_property_values(("location", "description"))
+    assert column == ("A rather large house",)
+
+    s = db.execute_query("SELECT TestHeight.description FROM "
+                         "RECORD TestWindow", unique=True)
+    column = s.get_property_values(("TestHeight", "description"))
+    assert column == ('TestHeightDesc',)
+
+    s = db.execute_query("SELECT TestWindow.TestHeight.description FROM "
+                         "RECORD TestHouse", unique=True)
+    # current limitation of get_property_values - no lists
+    # column = s.get_property_values(("TestWindow", "TestHeight", "description"))
+    # assert column == ('TestHeightDesc',)
+    assert s.get_property_values(("TestWindow"))[0][0].get_property(
+        "TestHeight").description == "TestHeightDesc"
+
+
 def test_select_id():
     house_id = db.execute_query("FIND RECORD TestHouse", unique=True).id
     s = db.execute_query("SELECT id FROM RECORD TestHouse", unique=True)
@@ -292,17 +387,43 @@ def test_select_id():
     column = s.get_property_values("id")
     assert column == (height_id,)
 
-    s = db.execute_query("SELECT TestWindow.TestHeight.id FROM "
+    s = db.execute_query("SELECT TestDoor.TestHeight.id FROM "
                          "RECORD TestHouse", unique=True)
-    column = s.get_property_values(("TestWindow", "TestHeight", "id"))
+    column = s.get_property_values(("TestDoor", "TestHeight", "id"))
     assert column == (height_id,)
 
-    s = db.execute_query("SELECT TestHeight.id.TestWindow FROM "
-                         "RECORD TestWindow", unique=True)
-    column = s.get_property_values(("TestHeight", "id", "TestWindow"))
+    s = db.execute_query("SELECT TestHeight.id.TestDoor FROM "
+                         "RECORD TestDoor", unique=True)
+    column = s.get_property_values(("TestHeight", "id", "TestDoor"))
     assert column == (None,)
 
 
+def test_select_id_list():
+    house_id = db.execute_query("FIND RECORD TestHouse", unique=True).id
+    s = db.execute_query("SELECT id FROM RECORD TestHouse", unique=True)
+    column = s.get_property_values("id")
+    assert column == (house_id,)
+
+    s = db.execute_query(
+        "SELECT location.id FROM RECORD TestHouse",
+        unique=True)
+    column = s.get_property_values("id")
+    assert column == (house_id,)
+
+    height_id = db.execute_query("FIND PROPERTY TestHeight", unique=True).id
+    s = db.execute_query("SELECT id FROM PROPERTY TestHeight", unique=True)
+    column = s.get_property_values("id")
+    assert column == (height_id,)
+
+    s = db.execute_query("SELECT TestWindow.TestHeight.id FROM "
+                         "RECORD TestHouse", unique=True)
+    # current limitation of get_property_values - no lists
+    # column = s.get_property_values(("TestWindow", "TestHeight", "id"))
+    # assert column == (height_id,)
+    assert s.get_property_values(("TestWindow"))[0][0].get_property(
+        "TestHeight").id == height_id
+
+
 def test_select_name():
     s = db.execute_query("SELECT name FROM RECORD TestHouse", unique=True)
     column = s.get_property_values("name")
@@ -317,12 +438,84 @@ def test_select_name():
     column = s.get_property_values("name")
     assert column == ("TestHeight",)
 
-    s = db.execute_query("SELECT TestWindow.TestHeight.name FROM "
+    s = db.execute_query("SELECT TestDoor.TestHeight.name FROM "
                          "RECORD TestHouse", unique=True)
-    column = s.get_property_values(("TestWindow", "TestHeight", "name"))
+    column = s.get_property_values(("TestDoor", "TestHeight", "name"))
     assert column == ("TestHeight",)
 
-    s = db.execute_query("SELECT TestHeight.name.TestWindow FROM "
-                         "RECORD TestWindow", unique=True)
-    column = s.get_property_values(("TestHeight", "name", "TestWindow"))
+    s = db.execute_query("SELECT TestHeight.name.TestDoor FROM "
+                         "RECORD TestDoor", unique=True)
+    column = s.get_property_values(("TestHeight", "name", "TestDoor"))
     assert column == (None,)
+
+
+def test_select_name_list():
+    s = db.execute_query("SELECT name FROM RECORD TestHouse", unique=True)
+    column = s.get_property_values("name")
+    assert column == ("Buckingham Palace",)
+
+    s = db.execute_query("SELECT location.name FROM RECORD TestHouse",
+                         unique=True)
+    column = s.get_property_values("name")
+    assert column == ("Buckingham Palace",)
+
+    s = db.execute_query("SELECT name FROM PROPERTY TestHeight", unique=True)
+    column = s.get_property_values("name")
+    assert column == ("TestHeight",)
+
+    s = db.execute_query("SELECT TestWindow.TestHeight.name FROM "
+                         "RECORD TestHouse", unique=True)
+    # current limitation of get_property_values - no lists
+    # column = s.get_property_values(("TestWindow", "TestHeight", "name"))
+    # assert column == ("TestHeight",)
+    assert s.get_property_values(("TestWindow"))[0][0].get_property(
+        "TestHeight").name == "TestHeight"
+
+
+def test_select_with_subtyping_semantics():
+    s = db.execute_query(
+        "SELECT name FROM RECORD TestHouse WITH TestHousePart",
+        unique=True)
+    column = s.get_property_values("name")
+    assert column == ("Buckingham Palace",)
+
+    s = db.execute_query(
+        "SELECT TestDoor.TestHeight FROM RECORD TestHouse WITH TestHousePart",
+        unique=True)
+    column = s.get_property_values(("TestDoor", "TestHeight"))
+    assert column == (21.5,)
+
+    s = db.execute_query(
+        "SELECT TestHousePart.TestHeight FROM RECORD TestHouse WITH TestHousePart",
+        unique=True)
+    column = s.get_property_values(("TestHousePart", "TestHeight"))
+    # this is a current limitation of get_property_values which will only
+    # return the value of the first matching property
+    # assert column == ([[20.5], 21.5,])
+
+    assert len(s.properties) == 2
+    # both the door and the window have been returned
+    print(s.properties[0].value)
+    assert (s.properties[0].name,
+            s.properties[1].name) == ("TestHousePart", "TestHousePart")
+    assert (s.properties[0].value[0].properties[0].value,
+            s.properties[1].value.properties[0].value) == (20.5, 21.5)
+
+
+def test_select_with_subtyping_semantics_second_level():
+    s = db.execute_query(
+        "SELECT TestHousePart.TestHouseProperty FROM RECORD TestHouse WITH TestHousePart",
+        unique=True)
+
+    assert len(s.properties) == 2
+    # both the door and the window have been returned
+    assert (s.properties[0].name,
+            s.properties[1].name) == ("TestHousePart", "TestHousePart")
+    assert (s.properties[0].value[0].properties[0].value,
+            s.properties[1].value.properties[0].value) == (20.5, 21.5)
+
+
+def test_select_with_subtyping_semantics_and_name_duplicates():
+    db.Property(name="TestHousePart", description="This is a duplicate",
+                datatype=db.TEXT).insert(unique=False)
+    test_select_with_subtyping_semantics()
diff --git a/tests/test_server_side_scripting.py b/tests/test_server_side_scripting.py
index 7ecc50121a2e2fc2eaaf3d31659d5ff0bc2bc604..96172dd2fcbe8bfbe6fce1f2ca1494e410c561d6 100644
--- a/tests/test_server_side_scripting.py
+++ b/tests/test_server_side_scripting.py
@@ -27,25 +27,34 @@ Integration tests for the implementation of the server-side-scripting api.
 """
 from __future__ import print_function, unicode_literals
 import os
-from pytest import raises
+import tempfile
+from pytest import raises, mark
 import json
 from lxml import etree
 from http.client import HTTPSConnection
 import ssl
 from caosdb import get_connection, get_config, Info, execute_query, RecordType
-from caosdb.exceptions import (EntityDoesNotExistError, ClientErrorException)
+from caosdb.exceptions import (HTTPClientError,
+                               HTTPResourceNotFoundError)
 from caosdb.connection.encode import MultipartParam, multipart_encode
 from caosdb.connection.utils import urlencode, urlparse
 from caosdb import administration as admin
 from caosdb.utils.server_side_scripting import run_server_side_script
 
 _TEST_SCRIPTS = ["not_executable", "ok", "err", "ok_anonymous"]
-_SERVER_SIDE_SCRIPTING_BIN_DIR_LOCAL = get_config().get(
-    "IntegrationTests",
-    "test_server_side_scripting.bin_dir.local")
-_SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER = get_config().get(
-    "IntegrationTests",
-    "test_server_side_scripting.bin_dir.server")
+
+try:
+    _SERVER_SIDE_SCRIPTING_BIN_DIR_LOCAL = get_config().get(
+        "IntegrationTests",
+        "test_server_side_scripting.bin_dir.local")
+except Exception:
+    _SERVER_SIDE_SCRIPTING_BIN_DIR_LOCAL = tempfile.mkdtemp()
+try:
+    _SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER = get_config().get(
+        "IntegrationTests",
+        "test_server_side_scripting.bin_dir.server")
+except Exception:
+    _SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER = ""
 _TEST_SCRIPTS_DIR = "./resources/"
 _REMOVE_FILES_AFTERWARDS = []
 _ORIGINAL_SERVER_SCRIPTING_BIN_DIR = ""
@@ -108,20 +117,22 @@ def teardown_module():
 def test_call_script_non_existing():
     form = dict()
     form["call"] = "non_existing_script"
-    with raises(EntityDoesNotExistError):
+    with raises(HTTPResourceNotFoundError):
         get_connection().post_form_data("scripting", form)
 
 
+@mark.local_server
 def test_call_script_not_executable():
     admin.set_server_property("SERVER_SIDE_SCRIPTING_BIN_DIRS",
                               _SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER)
     form = dict()
     form["call"] = "not_executable"
-    with raises(ClientErrorException) as exc_info:
+    with raises(HTTPClientError) as exc_info:
         get_connection().post_form_data("scripting", form)
     assert "not executable" in exc_info.value.body.decode("utf-8")
 
 
+@mark.local_server
 def test_call_ok():
     admin.set_server_property("SERVER_SIDE_SCRIPTING_BIN_DIRS",
                               _SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER)
@@ -135,6 +146,7 @@ def test_call_ok():
     assert xml.xpath("/Response/script/@code")[0] == "0"
 
 
+@mark.local_server
 def test_call_err():
     admin.set_server_property("SERVER_SIDE_SCRIPTING_BIN_DIRS",
                               _SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER)
@@ -276,6 +288,7 @@ def test_diagnostics_with_file_upload():
     assert xml.xpath("/Response/script/stderr")[0].text is None
 
 
+@mark.local_server
 def test_call_as_anonymous_with_administration_role():
     assert Info().user_info.roles == ["administration"]
 
@@ -351,6 +364,7 @@ def test_anonymous_script_calling_not_permitted():
     assert response.getheader("Set-Cookie") is None  # no auth token returned
 
 
+@mark.local_server
 def test_anonymous_script_calling_success():
     admin.set_server_property("SERVER_SIDE_SCRIPTING_BIN_DIRS",
                               _SERVER_SIDE_SCRIPTING_BIN_DIR_SERVER)
@@ -396,5 +410,5 @@ def test_evil_path():
             _SERVER_SIDE_SCRIPTING_BIN_DIR_LOCAL,
             "ok"))
 
-    with raises(EntityDoesNotExistError):
+    with raises(HTTPResourceNotFoundError):
         r = run_server_side_script("../ok")
diff --git a/tests/test_tickets.py b/tests/test_tickets.py
index 3afd753beae2673eba0387e657a2292f127097bb..cdaee95f647cec1574563b08922a7d9be08bad07 100644
--- a/tests/test_tickets.py
+++ b/tests/test_tickets.py
@@ -26,12 +26,13 @@
 @author: tf
 """
 import caosdb as db
-from caosdb.exceptions import (AmbiguityException, CaosDBException,
-                               EntityDoesNotExistError, EntityError,
+from caosdb.exceptions import (CaosDBException,
                                TransactionError, UniqueNamesError)
 from nose.tools import (assert_equal, assert_false, assert_is_none,
                         assert_is_not_none, assert_raises, assert_true,
                         nottest)
+import pytest
+from tests import test_misc
 
 
 def setup():
@@ -52,75 +53,74 @@ def test_ticket_103a():
         # insert w/o strict flag
         haswarnings = False
         rt.insert(strict=False)
-        assert_true(rt.is_valid())
+        assert rt.is_valid()
 
         for w in rt.get_warnings():
             haswarnings = True
 
             break
-        assert_true(haswarnings)
+        assert haswarnings
 
         # update w/o strict flag
         haswarnings = False
         rt.name = "TestRecordTypeUpdate"
         rt.update(strict=False)
-        assert_true(rt.is_valid())
+        assert rt.is_valid()
 
         for w in rt.get_warnings():
             haswarnings = True
 
             break
-        assert_true(haswarnings)
+        assert haswarnings
 
         # update w/ strict flag
         rt.name = "TestRecordTypeUpdate2"
-        try:
+        with pytest.raises(TransactionError) as e:
             rt.update(strict=True)
-            assert_true(False, "This should have raised an 128-Error (strict)")
-        except TransactionError as exc:
-            print(exc)
-            assert_equal(128, int(exc.get_code()))
-            rt = exc.get_entities()[0]
-        assert_false(rt.is_valid())
+        exc = e.value
+        print(exc)
+        assert 128 == int(exc.errors[0].code)
+        rt = exc.entities[0]
+        assert not rt.is_valid()
 
         for w in rt.get_warnings():
             haswarnings = True
 
             break
-        assert_true(haswarnings)
+        assert haswarnings
 
         for w in rt.get_errors():
-            if w.get_code() == 128:
+            if int(w.get_code()) == 128:
                 hasstricterror = True
 
                 break
-        assert_true(hasstricterror)
+        assert hasstricterror
     finally:
         try:
             rt.delete()
         except BaseException:
             pass
 
-    # insert w/ strict flag
+    # insert w/ strict flag without raising an exception
     haswarnings = False
     hasstricterror = False
     rt = db.RecordType(name="TestRecordType")
     try:
         rt.insert(strict=True, raise_exception_on_error=False)
-        assert_false(rt.is_valid())
+        assert not rt.is_valid()
 
         for w in rt.get_warnings():
             haswarnings = True
 
             break
-        assert_true(haswarnings)
+        assert haswarnings
 
         for w in rt.get_errors():
             if w.get_code() == 128:
                 hasstricterror = True
 
                 break
-        assert_true(hasstricterror)
+        assert hasstricterror
     finally:
         try:
             rt.delete()
@@ -148,19 +148,17 @@ def test_ticket_103b():
     # unique flag
 
     try:
-        rt1 = db.RecordType(name="NameDuplicatesEntity")
-        rt2 = db.RecordType(name="NameDuplicatesEntity")
+        rt1 = db.RecordType(name="TestNameDuplicatesEntity")
+        rt2 = db.RecordType(name="TestNameDuplicatesEntity")
 
         rt1.insert(
             unique=True, strict=False)
-        assert_true(rt1.is_valid())
-        try:
+        assert rt1.is_valid()
+        with pytest.raises(TransactionError) as te:
             rt2.insert(unique=True)
-            assert_true(False)
-        except UniqueNamesError:
-            pass
+        assert te.value.has_error(UniqueNamesError)
 
-        assert_false(rt2.is_valid())
+        assert not rt2.is_valid()
 
     finally:
         try:
@@ -173,24 +171,6 @@ def test_ticket_103b():
             pass
 
 
-def test_ticket_102():
-    """EntityDoesNotExistException."""
-
-    try:
-        p = db.Property(name="Non-ExistentProperty")
-        p.retrieve(
-            unique=True, raise_exception_on_error=True)
-        assert_true(False)
-    except CaosDBException as e:
-        assert_true(isinstance(e, EntityDoesNotExistError))
-        assert_is_not_none(e.get_entity())
-        assert_equal(e.get_entity().name, p.name)
-        assert_true(e.get_entity().has_errors())
-        assert_false(p.has_errors())
-        assert_false(p.is_valid())
-        assert_false(e.get_entity().is_valid())
-
-
 def test_ticket_101():
     """RecordType and Property constructor work differently?"""
 
@@ -224,35 +204,6 @@ def test_ticket_100():
             pass
 
 
-def test_ticket_96():
-
-    try:
-        rt1 = db.RecordType(name="a_b")
-        rt2 = db.RecordType(name="a_b")
-        rt1.insert()
-        rt2.insert(unique=False)
-
-        c = db.Container().append(
-            db.RecordType(name="a_b")).retrieve(unique=False)
-        assert_equal(len(c), 2)
-
-        try:
-            c = db.Container().append(
-                db.RecordType(name="a_b")).retrieve(unique=True)
-            assert_true(False)
-        except AmbiguityException as e:
-            print(repr(e))
-    finally:
-        try:
-            rt2.delete()
-        except BaseException:
-            pass
-        try:
-            rt1.delete()
-        except BaseException:
-            pass
-
-
 def test_ticket_114():
     try:
         db.execute_query("FIND rt_nice").delete()
@@ -579,7 +530,7 @@ def test_ticket_39():
 
     scratch = os.path.realpath(db.get_config().get(
         "EndToEndTests", "test_tickets.test_ticket_39.scratch"))
-    assert_true(os.path.isdir(scratch))
+    assert os.path.isdir(scratch)
     testfile = os.path.join(scratch, "test.dat")
     try:
         # insert RecordType
@@ -590,19 +541,16 @@ def test_ticket_39():
         # check if the server can connect to this filesystem
 
         f = db.File(path="testfiles/file1", pickup=testfile).insert()
-        assert_true(f.is_valid())
+        assert f.is_valid()
         f.delete()
 
         # make unreadable
         os.chmod(testfile, 0o000)
-        try:
+        with pytest.raises(TransactionError) as te:
             f = db.File(
                 path="testfiles/file1", pickup=testfile).insert()
-        except EntityError as e:
-            assert_equal(
-                "Insufficient read permission for this file. "
-                "Please make it readable.",
-                e.msg)
+        e = te.value.errors[0]
+        assert e.msg == "Insufficient read permission for this file. Please make it readable."
 
     finally:
         os.chmod(testfile, 0o600)
@@ -620,7 +568,7 @@ def test_ticket_128():
     try:
         db.execute_query(r"FIND 5\#):xw;;-`;BY6~PjsI^*g.$+eY#n.aA9zm")
     except TransactionError as e:
-        assert_equal(13, int(e.get_error().code))
+        assert 13 == int(e.error.code)
 
 
 def test_ticket_123a():
@@ -767,6 +715,7 @@ def test_ticket_143():
             pass
 
 
+@pytest.mark.slow
 def test_ticket_147():
 
     try:
@@ -925,13 +874,10 @@ def test_ticket_147():
         assert_equal(r21.id, s[0].id)
 
         # typo: SMALLES
-        try:
+        with pytest.raises(TransactionError):
             s = db.execute_query(
                 "FIND ticket147_Fre* WHICH HAS THE SMALLEST ticket147_ObstacleRadius AND A PROPERTY ( ticket147_BarkleyModelSimulation WHICH HAS THE SMALLES ticket147_TimeStep)"
             )
-            raise AssertionError("This should raise a TransactionError")
-        except TransactionError:
-            pass
 
     finally:
         try:
@@ -1148,28 +1094,6 @@ def test_ticket_166():
             pass
 
 
-def test_ticket_161():
-
-    try:
-        rt = db.RecordType(name="RecordTypeTest")
-        rt.insert()
-
-        assert_true(rt.is_valid())
-
-        rt2 = db.RecordType(name="RecordTypeTest")
-        assert_raises(UniqueNamesError, rt2.insert)
-
-    finally:
-        try:
-            rt2.delete()
-        except BaseException:
-            pass
-        try:
-            rt.delete()
-        except BaseException:
-            pass
-
-
 def test_ticket_178():
     from lxml import etree
 
diff --git a/tests/test_tickets_200.py b/tests/test_tickets_200.py
index 19255cc9f3a9cb74468bfd58454f6e2726e0ba40..1b242c865f9020be629a5a86efd0016edeca74fa 100644
--- a/tests/test_tickets_200.py
+++ b/tests/test_tickets_200.py
@@ -25,13 +25,12 @@
 """
 from __future__ import print_function, unicode_literals
 
-from nose.tools import (assert_equal, assert_is_none,  # @UnresolvedImport
-                        assert_is_not_none, assert_raises, assert_true,
-                        nottest)
+from nose.tools import (assert_equal, assert_is_none, assert_is_not_none,
+                        assert_true)
 from pytest import raises
 
 import caosdb as h
-from caosdb.common.models import Container, Property, RecordType
+from caosdb.common.models import Property, RecordType
 
 
 def setup_module():
@@ -199,7 +198,7 @@ def test_ticket_232():
     for i in range(1000):
         uri.append("longname" + str(i))
 
-    # with raises(h.URITooLongException) as exc_info:
+    # with raises(h.HTTPURITooLongError) as exc_info:
     #    h.get_connection().retrieve(uri)
 
     c = h.Container().extend(uri).retrieve(raise_exception_on_error=False)
@@ -327,10 +326,11 @@ def test_ticket_239():
             p, value="SimpleRecord3")
 
         c = h.Container().extend([rec4])
-        assert_raises(h.TransactionError, c.insert)
-        assert_equal(c[0].get_property(
-            "SimpleReferenceProperty").get_errors()[0].description,
-            "Referenced entity does not exist.")
+        with raises(h.TransactionError) as te:
+            c.insert()
+        assert te.value.has_error(h.UnqualifiedPropertiesError)
+        assert c[0].get_property("SimpleReferenceProperty").get_errors()[
+            0].description == "Referenced entity does not exist."
 
         rec3 = h.Record(name="SimpleRecord3").add_parent(rt)
         c = h.Container().extend([rec3, rec4]).insert()
@@ -570,5 +570,9 @@ def test_ticket_233():
     e1 = h.Entity("sdlkavhjawriluvyruksvnkuhndb")
     e2 = h.Entity("ösdlkavhjawriluvyruksvnkuhndb")
 
-    assert_raises(h.EntityDoesNotExistError, e1.retrieve)
-    assert_raises(h.EntityDoesNotExistError, e2.retrieve)
+    with raises(h.TransactionError) as te:
+        e1.retrieve()
+    assert te.value.has_error(h.EntityDoesNotExistError)
+    with raises(h.TransactionError) as te:
+        e2.retrieve()
+    assert te.value.has_error(h.EntityDoesNotExistError)
diff --git a/tests/test_tickets_300.py b/tests/test_tickets_300.py
index 1b36d343d5b84f3223ad93fc0366ba3535aa70aa..43fbd97f0fc3ea67e23736657d9cac07886fff35 100644
--- a/tests/test_tickets_300.py
+++ b/tests/test_tickets_300.py
@@ -5,6 +5,8 @@
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+# Copyright (C) 2020 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -25,12 +27,12 @@
 
 from __future__ import unicode_literals, print_function
 import caosdb as db
-from nose.tools import with_setup, assert_raises as raiz, assert_equal as eq
+from pytest import raises
 
 
 def _delete_test_entities():
     try:
-        db.execute_query("FIND Entity WITH id >= 100").delete()
+        db.execute_query("FIND Test*").delete()
     except Exception as e:
         print(e)
 
@@ -43,14 +45,23 @@ def teardown_module():
     _delete_test_entities()
 
 
-@with_setup(_delete_test_entities, _delete_test_entities)
+def setup():
+    setup_module()
+
+
+def teardown():
+    teardown_module()
+
+
 def test_ticket_350_insert_with_invalid_ref():
     c = db.Container()
-    e = db.Entity(name="SomeName")
-    rt1 = db.RecordType(name="RT1")
-    rt2 = db.RecordType(name="RT2").add_property(name="RT1", value="SomeName")
+    e = db.Entity(name="TestEnt")
+    rt1 = db.RecordType(name="TestRT1")
+    rt2 = db.RecordType(name="TestRT2").add_property(
+        name="TestRT1", value="TestEnt")
     c.extend([e, rt1, rt2])
-    with raiz(db.TransactionError) as cm:
+    with raises(db.TransactionError) as cm:
         c.insert()
-    eq(cm.exception.errors[0].msg, "There is no such role 'Entity'.")
-    eq(cm.exception.errors[1].msg, "Entity has unqualified properties.")
+    assert any(
+        [x.msg == "There is no such role 'Entity'." for x in cm.value.errors])
+    assert cm.value.has_error(db.UnqualifiedPropertiesError)
diff --git a/tests/test_version.py b/tests/test_version.py
index 784c23b0754ad4f9710ced3930a776af7a2747ee..2b8aafa882832a419fe1b796a703b0b31cb3b766 100644
--- a/tests/test_version.py
+++ b/tests/test_version.py
@@ -22,7 +22,6 @@
 # ** end header
 #
 from pytest import mark, raises
-from dateutil.parser import parse
 import caosdb as c
 
 
@@ -212,10 +211,10 @@ def test_retrieve_relative_to_head():
     assert first_version == rt_head.version, "head is first version"
 
     # no HEAD~1 before first update
-    with raises(c.EntityDoesNotExistError) as exc:
+    with raises(c.TransactionError) as exc:
         # no head~2
         c.Container().retrieve(query=str(rt.id) + "@HEAD~1", sync=False)
-
+    assert exc.value.has_error(c.EntityDoesNotExistError)
     # update
     rt.description = "TestDescription4"
     rt.update()
@@ -244,9 +243,10 @@ def test_retrieve_relative_to_head():
     assert rt_pre_head.version.successors[0].id == rt_new_head.version.id, (
         "successor of head~1 is head")
 
-    with raises(c.EntityDoesNotExistError) as exc:
+    with raises(c.TransactionError) as exc:
         # no head~2
         c.Container().retrieve(query=str(rt.id) + "@HEAD~2", sync=False)
+    assert exc.value.has_error(c.EntityDoesNotExistError)
 
 
 @mark.xfail(reason="bug fix needed")
@@ -263,9 +263,10 @@ def test_bug_cached_delete():
 
     c.execute_query("FIND RecordType TestRT").delete()
 
-    with raises(c.EntityDoesNotExistError) as exc:
+    with raises(c.TransactionError) as exc:
         c.Container().retrieve(query=str(rt.id) + "@" + old_version,
                                sync=False)[0]
+    assert exc.value.has_error(c.EntityDoesNotExistError)
 
 
 @mark.xfail(reason=("TODO: What is the desired behavior? "
@@ -458,7 +459,7 @@ def test_reference_deleted_in_old_version():
     rec.remove_property(ref_rt)
     rec.update()
 
-    with raises(c.EntityDoesNotExistError) as exc:
+    with raises(c.EmptyUniqueQueryError) as exc:
         c.execute_query(
             "FIND RECORD TestRec2 WHICH REFERENCES {}".format(
                 referenced_rec.id),
@@ -499,12 +500,13 @@ def test_reference_deleted_in_old_version():
     assert old_rec.get_property(p).value == "blablabla"
     assert old_rec.get_property(ref_rt).value == referenced_id
 
-    with raises(c.EntityDoesNotExistError) as exc:
+    with raises(c.EmptyUniqueQueryError) as exc:
         c.execute_query("FIND ENTITY WITH ID = {}".format(referenced_id),
                         unique=True)
 
-    with raises(c.EntityDoesNotExistError) as exc:
+    with raises(c.TransactionError) as exc:
         c.Record(id=referenced_id).retrieve()
+    assert exc.value.has_error(c.EntityDoesNotExistError)
 
 
 def test_reference_version_head():
diff --git a/tests/test_xmlparsing.py b/tests/test_xmlparsing.py
index e387f25404ec8a87d9c0275c2c0c28234f07ecfb..50fbbfc07d37aeda1982c7db5c2fc256826a027c 100644
--- a/tests/test_xmlparsing.py
+++ b/tests/test_xmlparsing.py
@@ -25,8 +25,10 @@
 
 @author: tf
 """
+import pytest
 
 
+@pytest.mark.local_server
 def test_parse_xml():
     from lxml import etree
     from nose.tools import assert_equal  # @UnresolvedImport
diff --git a/tox.ini b/tox.ini
index babdf47e254755b64599e386c96c708bca2b043c..26c5d1594c48fe755a355a3aee711fd6608c6f97 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,9 @@
 [tox]
-envlist=py36, py37, py38
+envlist=py36, py37, py38, py39
 skip_missing_interpreters = true
 [testenv]
 setenv = PASSWORD_STORE_DIR = {env:HOME}/.password-store
+passenv = PYCAOSDBINI
 deps=pytest
     nose
     pytest-cov