diff --git a/mutalyzer/ncbi.py b/mutalyzer/ncbi.py
index f131088ae89c6515d80d04e2ba5b11ebee8786c8..62c96c5b8cdf989e229d8d3544e67218d9774ade 100644
--- a/mutalyzer/ncbi.py
+++ b/mutalyzer/ncbi.py
@@ -3,15 +3,14 @@ Communication with the NCBI.
 """
 
 
-import functools
-
 from Bio import Entrez
 
 from .config import settings
 from .redisclient import client as redis
 
 
-def _get_link(source_accession, source_db, target_db, match_link_name):
+def _get_link(source_accession, source_db, target_db, match_link_name,
+              source_version=None, match_version=True):
     """
     Retrieve a linked accession number from the NCBI.
 
@@ -22,88 +21,142 @@ def _get_link(source_accession, source_db, target_db, match_link_name):
     :arg function match_link_name: For each link found, this function is
       called with the link name (`str`) and it should return `True` iff the
       link is to be used.
-
-    :returns: Linked accession number (without version number) or `None` if no
-      link can be found.
-    :rtype: str
+    :arg int source_version: Optional version number for `source_accession`.
+    :arg bool match_version: If `False`, the link does not have to match
+      `source_version`.
+
+    :returns: Tuple of `(target_accession, target_version)` representing the
+      link target, or `None` if no link can be found. If `source_version` is
+      not specified or `match_version` is `False`, `target_version` can be
+      `None`.
+    :rtype: tuple(str, int)
     """
     Entrez.email = settings.EMAIL
-    handle = Entrez.esearch(db=source_db, term=source_accession)
+
+    # If we are currently strictly matching on version, we can try again if
+    # no result is found. Otherwise, we just report failure.
+    def fail_or_retry():
+        if source_version is None or match_version:
+            return None
+        return _get_link(source_accession, source_db, target_db,
+                         match_link_name, source_version=None,
+                         match_version=False)
+
+    if source_version is None:
+        source = source_accession
+    else:
+        source = '%s.%d' % (source_accession, source_version)
+
+    # Find source record.
+    handle = Entrez.esearch(db=source_db, term=source)
     try:
         result = Entrez.read(handle)
     except Entrez.Parser.ValidationError:
-        return None
+        return fail_or_retry()
     finally:
         handle.close()
 
     try:
         source_gi = unicode(result['IdList'][0])
     except IndexError:
-        return None
+        return fail_or_retry()
 
+    # Find link from source record to target record.
     handle = Entrez.elink(dbfrom=source_db, db=target_db, id=source_gi)
     try:
         result = Entrez.read(handle)
     except Entrez.Parser.ValidationError:
-        return None
+        return fail_or_retry()
     finally:
         handle.close()
 
     if not result[0]['LinkSetDb']:
-        return None
+        return fail_or_retry()
 
     for link in result[0]['LinkSetDb']:
         if match_link_name(unicode(link['LinkName'])):
             target_gi = unicode(link['Link'][0]['Id'])
             break
     else:
-        return None
+        return fail_or_retry()
 
+    # Get target record.
     handle = Entrez.efetch(
         db=target_db, id=target_gi, rettype='acc', retmode='text')
-    target_accession = unicode(handle.read()).split('.')[0]
+    target = unicode(handle.read()).strip().split('.')
     handle.close()
-    return target_accession
 
+    target_accession = target[0]
+    target_version = int(target[1]) if source_version is not None else None
+    return target_accession, target_version
 
-def cache_link(source, target):
-    """
-    Decorator to add caching to link retrieval.
 
-    :arg str source: Source database (used to construct cache key).
-    :arg str target: Target database (used to construct cache key).
+def _get_link_cached(forward_key, reverse_key, source_accession, source_db,
+                     target_db, match_link_name, source_version=None,
+                     match_version=True):
     """
-    forward_key = 'ncbi:%s-to-%s:%%s' % (source, target)
-    reverse_key = 'ncbi:%s-to-%s:%%s' % (target, source)
+    Version of :func:`_get_link` with caching.
 
-    def cache_source_to_target(f):
-        @functools.wraps(f)
-        def cached_f(accession):
-            result = redis.get(forward_key % accession)
-            if result is not None:
-                # The empty string is a cached negative result, which we return as
-                # `None`.
-                return result or None
+    :arg str forward_key: Cache key format string for the forward direction.
+      The source term will be substituted in this template.
+    :arg str reverse_key: Cache key format string for the reverse direction.
+      The target term will be substituted in this template.
 
-            result = f(accession)
-
-            if result is None:
-                redis.setex(forward_key % accession,
-                            settings.NEGATIVE_LINK_CACHE_EXPIRATION, '')
-                return None
+    The cache value for a negative result (no link found) is the empty string
+    and expires in `NEGATIVE_LINK_CACHE_EXPIRATION` seconds.
+    """
+    if source_version is not None:
+        # Query cache for link with version.
+        target = redis.get(forward_key %
+                           ('%s.%d' % (source_accession, source_version)))
+        if target == '':
+            return None
+        if target:
+            target_accession, target_version = target.split('.')
+            return target_accession, int(target_version)
+
+    if source_version is None or not match_version:
+        # Query cache for link without version.
+        target = redis.get(forward_key % source_accession)
+        if target == '':
+            return None
+        if target is not None:
+            return target, None
+
+    # Query NCBI service.
+    try:
+        target_accession, target_version = _get_link(
+            source_accession, source_db, target_db, match_link_name,
+            source_version=source_version, match_version=match_version)
+    except TypeError:
+        # No link was found.
+        if source_version is not None:
+            # Store a negative forward link with version.
+            redis.setex(forward_key %
+                        ('%s.%d' % (source_accession, source_version)),
+                        settings.NEGATIVE_LINK_CACHE_EXPIRATION, '')
+        if source_version is None or not match_version:
+            # Store a negative forward link without version.
+            redis.setex(forward_key % source_accession,
+                        settings.NEGATIVE_LINK_CACHE_EXPIRATION, '')
+        return None
 
-            # We store the resulting link in both directions.
-            redis.set(forward_key % accession, result)
-            redis.set(reverse_key % result, accession)
-            return result
+    # Store the link without version in both directions.
+    redis.set(forward_key % source_accession, target_accession)
+    redis.set(reverse_key % target_accession, source_accession)
 
-        return cached_f
+    if source_version is not None and target_version is not None:
+        # Store the link with version in both directions.
+        redis.set(forward_key % ('%s.%d' % (source_accession, source_version)),
+                  '%s.%d' % (target_accession, target_version))
+        redis.set(reverse_key % ('%s.%d' % (target_accession, target_version)),
+                  '%s.%d' % (source_accession, source_version))
 
-    return cache_source_to_target
+    return target_accession, target_version
 
 
-@cache_link('transcript', 'protein')
-def transcript_to_protein(transcript_accession):
+def transcript_to_protein(transcript_accession, transcript_version=None,
+                          match_version=True):
     """
     Try to find the protein linked to a transcript.
 
@@ -113,18 +166,26 @@ def transcript_to_protein(transcript_accession):
 
     :arg str transcript_accession: Accession number of the transcript for
       which we want to find the protein (without version number).
-
-    :returns: Accession number of a protein (without version number) or `None`
-      if no link can be found.
-    :rtype: str
+    :arg int transcript_version: Transcript version number. Please provide
+      this if available, also if it does not need to match. This will enrich
+      the cache.
+    :arg bool match_version: If `False`, the link does not have to match
+      `transcript_version`.
+
+    :returns: Tuple of `(protein_accession, protein_version)` representing the
+      linked protein, or `None` if no link can be found. If `match_version` is
+      `False`, `protein_version` can be `None`.  TODO: can or will?
+    :rtype: tuple(str, int)
     """
-    return _get_link(
+    return _get_link_cached(
+        'ncbi:transcript-to-protein:%s', 'ncbi:protein-to-transcript:%s',
         transcript_accession, 'nucleotide', 'protein',
-        lambda link: link in ('nuccore_protein', 'nuccore_protein_cds'))
+        lambda link: link in ('nuccore_protein', 'nuccore_protein_cds'),
+        source_version=transcript_version, match_version=match_version)
 
 
-@cache_link('protein', 'transcript')
-def protein_to_transcript(protein_accession):
+def protein_to_transcript(protein_accession, protein_version=None,
+                          match_version=True):
     """
     Try to find the transcript linked to a protein.
 
@@ -134,11 +195,14 @@ def protein_to_transcript(protein_accession):
 
     :arg str protein_accession: Accession number of the protein for which we
       want to find the transcript (without version number).
+    TODO
 
     :returns: Accession number of a transcript (without version number) or
       `None` if no link can be found.
     :rtype: str
     """
-    return _get_link(
+    return _get_link_cached(
+        'ncbi:protein-to-transcript:%s', 'ncbi:transcript-to-protein:%s',
         protein_accession, 'protein', 'nucleotide',
-        lambda link: link == 'protein_nuccore_mrna')
+        lambda link: link == 'protein_nuccore_mrna',
+        source_version=protein_version, match_version=match_version)
diff --git a/mutalyzer/parsers/genbank.py b/mutalyzer/parsers/genbank.py
index 5312a1b5996106223c44809e1952f2d6be5d56c9..be3badbdbbc0900910810b07060370bfeb8d27ac 100644
--- a/mutalyzer/parsers/genbank.py
+++ b/mutalyzer/parsers/genbank.py
@@ -220,8 +220,14 @@ class GBparser():
                     i.proteinLink = i.protein_id.split('.')[0]
             #if
             else :                # Tag an mRNA with the protein id too.
-                i.proteinLink = \
-                    ncbi.transcript_to_protein(i.transcript_id.split('.')[0])
+                accession, version = i.transcript_id.split('.')
+                protein = ncbi.transcript_to_protein(
+                    accession, int(version), match_version=False)
+                if protein is None:
+                    i.proteinLink = None
+                else:
+                    # We ignore the version.
+                    i.proteinLink = protein[0]
             i.positionList = self.__locationList2posList(i)
             i.location = self.__location2pos(i.location) #FIXME
             #if not i.positionList : # FIXME ???
diff --git a/tests/fixtures.py b/tests/fixtures.py
index a3f5e363bfdf73d4ab65b724863c14995079b472..870331f86254165a066d73258427eff5c3c2fbd4 100644
--- a/tests/fixtures.py
+++ b/tests/fixtures.py
@@ -73,6 +73,35 @@ def available_references():
         return yaml.safe_load(f)
 
 
+def _add_links(settings, links):
+    """
+    Add transcript-protein links to the cache.
+    """
+    for transcript, protein in links:
+        if transcript is not None:
+            key = 'ncbi:transcript-to-protein:%s' % transcript
+            if protein is not None:
+                redis.set(key, protein)
+                if '.' in transcript:
+                    key = key.rsplit('.', 1)[0]
+                    redis.set(key, protein.rsplit('.', 1)[0])
+            else:
+                redis.setex(key,
+                            settings.NEGATIVE_LINK_CACHE_EXPIRATION,
+                            '')
+        if protein is not None:
+            key = 'ncbi:protein-to-transcript:%s' % protein
+            if transcript is not None:
+                redis.set(key, transcript)
+                if '.' in protein:
+                    key = key.rsplit('.', 1)[0]
+                    redis.set(key, transcript.rsplit('.', 1)[0])
+            else:
+                redis.setex(key,
+                            settings.NEGATIVE_LINK_CACHE_EXPIRATION,
+                            '')
+
+
 @pytest.fixture
 def references(request, settings, db, available_references):
     try:
@@ -99,23 +128,7 @@ def references(request, settings, db, available_references):
         references.append(Reference(
             accession, entry['checksum'], geninfo_identifier=geninfo_id))
 
-        for transcript_accession, protein_accession in entry.get('links', []):
-            if transcript_accession is not None:
-                key = 'ncbi:transcript-to-protein:%s' % transcript_accession
-                if protein_accession is not None:
-                    redis.set(key, protein_accession)
-                else:
-                    redis.setex(key,
-                                settings.NEGATIVE_LINK_CACHE_EXPIRATION,
-                                '')
-            if protein_accession is not None:
-                key = 'ncbi:protein-to-transcript:%s' % protein_accession
-                if transcript_accession is not None:
-                    redis.set(key, transcript_accession)
-                else:
-                    redis.setex(key,
-                                settings.NEGATIVE_LINK_CACHE_EXPIRATION,
-                                '')
+        _add_links(settings, entry.get('links', []))
 
     db.session.add_all(references)
     db.session.commit()
@@ -123,6 +136,17 @@ def references(request, settings, db, available_references):
     return references
 
 
+@pytest.fixture
+def links(request, settings, db, available_references):
+    try:
+        links = request.param
+    except AttributeError:
+        return []
+
+    _add_links(settings, links)
+    return links
+
+
 @pytest.fixture
 def hg19(db):
     """
@@ -573,3 +597,63 @@ def hg19_transcript_mappings(db, hg19):
         version=3))
 
     db.session.commit()
+
+
+def with_references(*references):
+    """
+    Convenience decorator for parameterizing tests with reference fixtures.
+
+    Allows us to write:
+
+        @with_references('NM_004006.1', 'NM_004006.2')
+        def test_references():
+            pass
+
+    Instead of:
+
+        @pytest.mark.usefixtures('references')
+        @pytest.mark.parametrize('references',
+                                 [['NM_004006.1', 'NM_004006.2']],
+                                 ids=['NM_004006.1,NM_004006.2'],
+                                 indirect=True)
+        def test_references():
+            pass
+
+    """
+    def test_with_references(test):
+        return pytest.mark.usefixtures('references')(
+            pytest.mark.parametrize('references', [references], indirect=True,
+                                    ids=[','.join(references)])(test))
+    return test_with_references
+
+
+def with_links(*links):
+    """
+    Convenience decorator for parameterizing tests with transcript-protein
+    link fixtures.
+
+    Allows us to write:
+
+        @with_links(('NM_018650', 'NP_061120'), ('NM_027221', None))
+        def test_links():
+            pass
+
+    Instead of:
+
+        @pytest.mark.usefixtures('links')
+        @pytest.mark.parametrize('links',
+                                 [('NM_018650', 'NP_061120'),
+                                  ('NM_027221', None)],
+                                 ids=['NM_018650/NP_061120,NM_027221/*'],
+                                 indirect=True)
+        def test_links():
+            pass
+
+    """
+    def test_with_links(test):
+        return pytest.mark.usefixtures('links')(
+            pytest.mark.parametrize(
+                'links', [links], indirect=True,
+                ids=[','.join('/'.join(a or '*' for a in l)
+                              for l in links)])(test))
+    return test_with_links
diff --git a/tests/test_ncbi.py b/tests/test_ncbi.py
index c8df1c6790a13adbd6239b4d6a71ecc5795fb676..2920bc420df661ef750f8d279179446a47802f86 100644
--- a/tests/test_ncbi.py
+++ b/tests/test_ncbi.py
@@ -5,33 +5,394 @@ Tests for the mutalyzer.ncbi module.
 
 from __future__ import unicode_literals
 
+import Bio.Entrez
 import pytest
 
 from mutalyzer import ncbi
+from mutalyzer.redisclient import client as redis
 
+from fixtures import with_links
 
-pytestmark = [
-    pytest.mark.usefixtures('references'),
-    pytest.mark.parametrize('references', [['MARK1']], indirect=True)
-]
 
+@pytest.fixture
+def entrez(request, monkeypatch):
+    """
+    Fixture monkey-patching the NCBI Entrez API to return transcript-protein
+    links defined in the fixture parameter.
 
-def test_transcript_to_protein():
+    The fixture is similar to the :func:`fixtures.links` fixture, but instead
+    of storing the links in the cache, the API is monkey-patched.
     """
-    Get protein for transcript.
+    try:
+        links = request.param
+    except AttributeError:
+        return []
+
+    # We need two-way lookup.
+    transcript_to_protein = dict(links)
+    protein_to_transcript = dict((p, t) for t, p in links)
+
+    # Store original methods which should be called as a fallback.
+    esearch = Bio.Entrez.esearch
+    elink = Bio.Entrez.elink
+    efetch = Bio.Entrez.efetch
+
+    # Intermediate Entrez result object which can be parsed with Entrez.read.
+    class EntrezResult(object):
+        def __init__(self, result):
+            self.result = result
+
+        def read(self):
+            return self.result
+
+        def close(self):
+            pass
+
+    def mock_esearch(db=None, term=None):
+        if ((db == 'nucleotide' and term in transcript_to_protein)
+                or (db == 'protein' and term in protein_to_transcript)):
+            return EntrezResult({
+                'Count': '1',
+                'RetMax': '1',
+                'IdList': [term],
+                'TranslationSet': [],
+                'RetStart': '0',
+                'QueryTranslation': ''
+            })
+        return esearch(db=db, term=term)
+
+    def mock_elink(dbfrom=None, db=None, id=None):
+        if dbfrom == 'nucleotide' and id in transcript_to_protein:
+            if transcript_to_protein[id] is None:
+                linkset = []
+            else:
+                linkset = [{'DbTo': 'protein',
+                            'Link': [{'Id': transcript_to_protein[id]}],
+                            'LinkName': 'nuccore_protein'}]
+            return EntrezResult([{
+                'LinkSetDb': linkset,
+                'DbFrom': 'nuccore',
+                'IdList': [id],
+                'LinkSetDbHistory': [],
+                'ERROR': []
+            }])
+        if dbfrom == 'protein' and id in protein_to_transcript:
+            if protein_to_transcript[id] is None:
+                linkset = []
+            else:
+                linkset = [{'DbTo': 'nuccore',
+                            'Link': [{'Id': '568815587'},
+                                     {'Id': '528476600'},
+                                     {'Id': '568815270'},
+                                     {'Id': '528474155'},
+                                     {'Id': '452415518'},
+                                     {'Id': '452405284'},
+                                     {'Id': '383209650'}],
+                            'LinkName': 'protein_nuccore'},
+                           {'DbTo': 'nuccore',
+                            'Link': [{'Id': '4506864'}],
+                            'LinkName': 'protein_nuccore_cds'},
+                           {'DbTo': 'nuccore',
+                            'Link': [{'Id': '48735311'},
+                                     {'Id': '48734961'},
+                                     {'Id': '47682402'},
+                                     {'Id': '18490203'},
+                                     {'Id': '16359050'},
+                                     {'Id': '16306997'},
+                                     {'Id': '15929518'},
+                                     {'Id': '15214938'},
+                                     {'Id': '13528941'}],
+                            'LinkName': 'protein_nuccore_mgc_refseq'},
+                           {'DbTo': 'nuccore',
+                            'Link': [{'Id': protein_to_transcript[id]}],
+                            'LinkName': 'protein_nuccore_mrna'}]
+            return EntrezResult([{
+                'LinkSetDb': linkset,
+                'DbFrom': 'protein',
+                'IdList': [id],
+                'LinkSetDbHistory': [],
+                'ERROR': []
+            }])
+        return elink(dbfrom=dbfrom, db=db, id=id)
+
+    def mock_efetch(db=None, id=None, rettype=None, retmode=None):
+        if ((db == 'nucleotide' and id in transcript_to_protein)
+                or (db == 'protein' and id in protein_to_transcript)):
+            if '.' not in id:
+                id += '.9999'
+            return EntrezResult(id + '\n')
+        return efetch(db=db, id=id, rettype=rettype, retmode=retmode)
+
+    def mock_read(result):
+        return result.read()
+
+    monkeypatch.setattr(Bio.Entrez, 'esearch', mock_esearch)
+    monkeypatch.setattr(Bio.Entrez, 'elink', mock_elink)
+    monkeypatch.setattr(Bio.Entrez, 'efetch', mock_efetch)
+    monkeypatch.setattr(Bio.Entrez, 'read', mock_read)
+    return links
+
+
+def with_entrez(*links):
+    """
+    Convenience decorator for parameterizing tests with transcript-protein
+    link fixtures in the Entrez API.
+
+    Similar to :func:`fixtures.with_links`.
     """
-    assert ncbi.transcript_to_protein('NM_018650') == 'NP_061120'
+    def test_with_entrez(test):
+        return pytest.mark.usefixtures('entrez')(
+            pytest.mark.parametrize(
+                'entrez', [links], indirect=True,
+                ids=[','.join('/'.join(a or '*' for a in l)
+                              for l in links)])(test))
+    return test_with_entrez
 
 
-def test_transcript_to_protein_negative():
+@with_entrez(('NM_11111.1', None),
+             ('NM_11111.2', 'NP_11111.2'),
+             ('NM_22222.2', None),
+             ('NM_22222.3', 'NP_22222.3'),
+             ('NM_33333.4', None),
+             ('NM_33333.5', 'NP_33333.5'),
+             ('NM_44444', None),
+             ('NM_44444.5', None),
+             ('NM_44444.6', None),
+             ('NM_55555', 'NP_55555'),
+             ('NM_55555.6', None),
+             ('NM_66666', 'NP_66666'),
+             ('NM_66666.6', 'NP_66666.6'),
+             ('NM_66666.7', 'NP_66666.7'),
+             ('NM_66666.8', None),
+             ('NM_77777', 'NP_77777'),
+             ('NM_77777.7', 'NP_77777.7'),
+             ('NM_77777.8', None),
+             ('NM_88888', None),
+             ('NM_88888.8', None),
+             ('NM_88888.9', 'NP_88888.9'))
+@with_links(('NM_11111', 'NP_11111'),
+            ('NM_22222', None),
+            ('NM_33333.3', 'NP_33333.3'),
+            ('NM_44444.4', None),
+            ('NM_55555.5', None),
+            ('NM_66666.6', None))
+@pytest.mark.parametrize('accession,version,match_version,expected', [
+    ('NM_11111', None, False, ('NP_11111', None)),
+    ('NM_11111', 1, False, ('NP_11111', None)),
+    ('NM_11111', 1, True, None),
+    ('NM_11111', 2, False, ('NP_11111', None)),
+    ('NM_11111', 2, True, ('NP_11111', 2)),
+    ('NM_22222', None, False, None),
+    ('NM_22222', 2, False, None),
+    ('NM_22222', 2, True, None),
+    ('NM_22222', 3, False, None),
+    ('NM_22222', 3, True, ('NP_22222', 3)),
+    ('NM_33333', None, False, ('NP_33333', None)),
+    ('NM_33333', 3, True, ('NP_33333', 3)),
+    ('NM_33333', 3, False, ('NP_33333', 3)),
+    ('NM_33333', 4, True, None),
+    ('NM_33333', 4, False, ('NP_33333', None)),
+    ('NM_33333', 5, True, ('NP_33333', 5)),
+    ('NM_33333', 5, False, ('NP_33333', None)),
+    ('NM_44444', None, False, None),
+    ('NM_44444', 4, True, None),
+    ('NM_44444', 4, False, None),
+    ('NM_44444', 5, True, None),
+    ('NM_44444', 5, False, None),
+    ('NM_44444', 6, True, None),
+    ('NM_44444', 6, False, None),
+    ('NM_55555', None, False, ('NP_55555', None)),
+    ('NM_55555', 5, True, None),
+    ('NM_55555', 5, False, None),
+    ('NM_55555', 6, True, None),
+    ('NM_55555', 6, False, ('NP_55555', None)),
+    ('NM_66666', None, False, ('NP_66666', None)),
+    ('NM_66666', 6, True, None),
+    ('NM_66666', 6, False, None),
+    ('NM_66666', 7, True, ('NP_66666', 7)),
+    ('NM_66666', 7, False, ('NP_66666', 7)),
+    ('NM_66666', 8, True, None),
+    ('NM_66666', 8, False, ('NP_66666', None)),
+    ('NM_77777', None, False, ('NP_77777', None)),
+    ('NM_77777', 7, False, ('NP_77777', 7)),
+    ('NM_77777', 7, True, ('NP_77777', 7)),
+    ('NM_77777', 8, False, ('NP_77777', None)),
+    ('NM_77777', 8, True, None),
+    ('NM_88888', None, False, None),
+    ('NM_88888', 8, False, None),
+    ('NM_88888', 8, True, None),
+    ('NM_88888', 9, False, ('NP_88888', 9)),
+    ('NM_88888', 9, True, ('NP_88888', 9))])
+def test_transcript_to_protein(accession, version, match_version, expected):
     """
-    Get no protein for transcript.
+    Get protein for transcript.
+
+    Both the Entrez API and our cache are fixed with a set of
+    transcript-protein links. This test is parametrized with a list of
+    arguments for the :func:`ncbi.transcript_to_protein` function and the
+    corresponding expected result.
     """
-    assert ncbi.transcript_to_protein('XM_005273133') is None
+    assert ncbi.transcript_to_protein(
+        accession, version, match_version) == expected
 
 
-def test_protein_to_transcript():
+@with_entrez((None, 'NP_11111.1'),
+             ('NM_11111.2', 'NP_11111.2'),
+             (None, 'NP_22222.2'),
+             ('NM_22222.3', 'NP_22222.3'),
+             (None, 'NP_33333.4'),
+             ('NM_33333.5', 'NP_33333.5'),
+             (None, 'NP_44444'),
+             (None, 'NP_44444.5'),
+             (None, 'NP_44444.6'),
+             ('NM_55555', 'NP_55555'),
+             (None, 'NP_55555.6'),
+             ('NM_66666', 'NP_66666'),
+             ('NM_66666.6', 'NP_66666.6'),
+             ('NM_66666.7', 'NP_66666.7'),
+             (None, 'NP_66666.8'),
+             ('NM_77777', 'NP_77777'),
+             ('NM_77777.7', 'NP_77777.7'),
+             (None, 'NP_77777.8'),
+             (None, 'NP_88888'),
+             (None, 'NP_88888.8'),
+             ('NM_88888.9', 'NP_88888.9'))
+@with_links(('NM_11111', 'NP_11111'),
+            (None, 'NP_22222'),
+            ('NM_33333.3', 'NP_33333.3'),
+            (None, 'NP_44444.4'),
+            (None, 'NP_55555.5'),
+            (None, 'NP_66666.6'))
+@pytest.mark.parametrize('accession,version,match_version,expected', [
+    ('NP_11111', None, False, ('NM_11111', None)),
+    ('NP_11111', 1, False, ('NM_11111', None)),
+    ('NP_11111', 1, True, None),
+    ('NP_11111', 2, False, ('NM_11111', None)),
+    ('NP_11111', 2, True, ('NM_11111', 2)),
+    ('NP_22222', None, False, None),
+    ('NP_22222', 2, False, None),
+    ('NP_22222', 2, True, None),
+    ('NP_22222', 3, False, None),
+    ('NP_22222', 3, True, ('NM_22222', 3)),
+    ('NP_33333', None, False, ('NM_33333', None)),
+    ('NP_33333', 3, True, ('NM_33333', 3)),
+    ('NP_33333', 3, False, ('NM_33333', 3)),
+    ('NP_33333', 4, True, None),
+    ('NP_33333', 4, False, ('NM_33333', None)),
+    ('NP_33333', 5, True, ('NM_33333', 5)),
+    ('NP_33333', 5, False, ('NM_33333', None)),
+    ('NP_44444', None, False, None),
+    ('NP_44444', 4, True, None),
+    ('NP_44444', 4, False, None),
+    ('NP_44444', 5, True, None),
+    ('NP_44444', 5, False, None),
+    ('NP_44444', 6, True, None),
+    ('NP_44444', 6, False, None),
+    ('NP_55555', None, False, ('NM_55555', None)),
+    ('NP_55555', 5, True, None),
+    ('NP_55555', 5, False, None),
+    ('NP_55555', 6, True, None),
+    ('NP_55555', 6, False, ('NM_55555', None)),
+    ('NP_66666', None, False, ('NM_66666', None)),
+    ('NP_66666', 6, True, None),
+    ('NP_66666', 6, False, None),
+    ('NP_66666', 7, True, ('NM_66666', 7)),
+    ('NP_66666', 7, False, ('NM_66666', 7)),
+    ('NP_66666', 8, True, None),
+    ('NP_66666', 8, False, ('NM_66666', None)),
+    ('NP_77777', None, False, ('NM_77777', None)),
+    ('NP_77777', 7, False, ('NM_77777', 7)),
+    ('NP_77777', 7, True, ('NM_77777', 7)),
+    ('NP_77777', 8, False, ('NM_77777', None)),
+    ('NP_77777', 8, True, None),
+    ('NP_88888', None, False, None),
+    ('NP_88888', 8, False, None),
+    ('NP_88888', 8, True, None),
+    ('NP_88888', 9, False, ('NM_88888', 9)),
+    ('NP_88888', 9, True, ('NM_88888', 9))])
+def test_protein_to_transcript(accession, version, match_version, expected):
     """
     Get transcript for protein.
+
+    Both the Entrez API and our cache are fixed with a set of
+    transcript-protein links. This test is parametrized with a list of
+    arguments for the :func:`ncbi.transcript_to_protein` function and the
+    corresponding expected result.
+
+    Fixtures and parameters of this test mirror those of the
+    `test_transcript_to_protein` test.
+    """
+    assert ncbi.protein_to_transcript(
+        accession, version, match_version) == expected
+
+
+@with_entrez(('NM_11111', None),
+             ('NM_22222', 'NP_22222'),
+             ('NM_33333', None),
+             ('NM_33333.3', None),
+             ('NM_44444', None),
+             ('NM_44444.4', 'NP_44444.4'))
+@pytest.mark.parametrize('accession,version,match_version,expected_forward,expected_reverse', [
+    ('NM_11111', None, False, [('NM_11111', None)], []),
+    ('NM_22222', None, False,
+     [('NM_22222', 'NP_22222')], [('NM_22222', 'NP_22222')]),
+    ('NM_33333', None, False, [('NM_33333', None)], []),
+    ('NM_33333', 3, False, [('NM_33333', None), ('NM_33333.3', None)], []),
+    ('NM_33333', 3, True, [('NM_33333.3', None)], []),
+    ('NM_44444', None, False, [('NM_44444', None)], []),
+    ('NM_44444', 4, False,
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')],
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')]),
+    ('NM_44444', 4, True,
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')],
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')])])
+def test_transcript_to_protein_cache(accession, version, match_version,
+                                     expected_forward, expected_reverse):
+    """
+    Get protein for transcript and check the resulting cache state.
     """
-    assert ncbi.protein_to_transcript('NP_061120') == 'NM_018650'
+    ncbi.transcript_to_protein(accession, version, match_version)
+
+    forward = [(key.split(':')[-1], redis.get(key) or None)
+               for key in redis.keys('ncbi:transcript-to-protein:*')]
+    assert sorted(forward) == sorted(expected_forward)
+
+    reverse = [(redis.get(key) or None, key.split(':')[-1])
+               for key in redis.keys('ncbi:protein-to-transcript:*')]
+    assert sorted(reverse) == sorted(expected_reverse)
+
+
+@with_entrez((None, 'NP_11111'),
+             ('NM_22222', 'NP_22222'),
+             (None, 'NP_33333'),
+             (None, 'NP_33333.3'),
+             (None, 'NP_44444'),
+             ('NM_44444.4', 'NP_44444.4'))
+@pytest.mark.parametrize('accession,version,match_version,expected_forward,expected_reverse', [
+    ('NP_11111', None, False, [], [(None, 'NP_11111')]),
+    ('NP_22222', None, False,
+     [('NM_22222', 'NP_22222')], [('NM_22222', 'NP_22222')]),
+    ('NP_33333', None, False, [], [(None, 'NP_33333')]),
+    ('NP_33333', 3, False, [], [(None, 'NP_33333'), (None, 'NP_33333.3')]),
+    ('NP_33333', 3, True, [], [(None, 'NP_33333.3')]),
+    ('NP_44444', None, False, [], [(None, 'NP_44444')]),
+    ('NP_44444', 4, False,
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')],
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')]),
+    ('NP_44444', 4, True,
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')],
+     [('NM_44444', 'NP_44444'), ('NM_44444.4', 'NP_44444.4')])])
+def test_protein_to_transcript_cache(accession, version, match_version,
+                                     expected_forward, expected_reverse):
+    """
+    Get transcript for protein and check the resulting cache state.
+    """
+    ncbi.protein_to_transcript(accession, version, match_version)
+
+    forward = [(key.split(':')[-1], redis.get(key) or None)
+               for key in redis.keys('ncbi:transcript-to-protein:*')]
+    assert sorted(forward) == sorted(expected_forward)
+
+    reverse = [(redis.get(key) or None, key.split(':')[-1])
+               for key in redis.keys('ncbi:protein-to-transcript:*')]
+    assert sorted(reverse) == sorted(expected_reverse)
diff --git a/tests/test_parsers_genbank.py b/tests/test_parsers_genbank.py
index e491b767fa237802053a488db873099ebca417ed..2248318e5ac7ff3c5080f4c1a413ddc36c833dd1 100644
--- a/tests/test_parsers_genbank.py
+++ b/tests/test_parsers_genbank.py
@@ -11,6 +11,8 @@ import pytest
 
 from mutalyzer.parsers.genbank import GBparser
 
+from fixtures import with_references
+
 
 @pytest.fixture
 def parser():
@@ -35,7 +37,7 @@ def test_product_lists_mismatch(parser, products, expected):
     assert parser._find_mismatch(products) == expected
 
 
-@pytest.mark.parametrize('references', [['A1BG']], indirect=True)
+@with_references('A1BG')
 def test_only_complete_genes_included(settings, references, parser):
     """
     Incomplete genes from the reference file should be ignored.
diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py
index 22c20b3c5bd5fcb5beee384b9b2d3b81be47c5f3..fa336f0f98f5ceae04cf7ce7bdd3a51fd592d80a 100644
--- a/tests/test_scheduler.py
+++ b/tests/test_scheduler.py
@@ -19,6 +19,8 @@ from mutalyzer import File
 from mutalyzer import output
 from mutalyzer import Scheduler
 
+from fixtures import with_references
+
 
 pytestmark = pytest.mark.usefixtures('db')
 
@@ -85,9 +87,7 @@ def test_large_input():
     _batch_job_plain_text(variants, expected, 'syntax-checker')
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['AB026906.1', 'NM_000059.3']],
-                         indirect=True)
+@with_references('AB026906.1', 'NM_000059.3')
 def test_name_checker():
     """
     Simple name checker batch job.
@@ -212,8 +212,7 @@ def test_name_checker_altered():
         _batch_job_plain_text(variants, expected, 'name-checker')
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_000059.3']], indirect=True)
+@with_references('NM_000059.3')
 def test_name_checker_skipped():
     """
     Name checker job with skipped entries.
diff --git a/tests/test_services_soap.py b/tests/test_services_soap.py
index f1964b302ca799aab096302059127c4f032d027c..5c100eb1e83318a7448cbfe9b75329b9f93488ee 100644
--- a/tests/test_services_soap.py
+++ b/tests/test_services_soap.py
@@ -20,6 +20,8 @@ import mutalyzer
 from mutalyzer.services.soap import application
 from mutalyzer import Scheduler
 
+from fixtures import with_references
+
 
 @pytest.fixture
 def server():
@@ -188,8 +190,7 @@ def test_gettranscriptsbygenename_invalid(api):
     assert not r
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['AF230870.1']], indirect=True)
+@with_references('AF230870.1')
 def test_gettranscriptsandinfo_valid(api):
     """
     Running getTranscriptsAndInfo with a valid genomic reference should
@@ -203,8 +204,7 @@ def test_gettranscriptsandinfo_valid(api):
         assert t in names
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_gettranscriptsandinfo_restricted_valid(api):
     """
     Running getTranscriptsAndInfo with a valid genomic reference and a
@@ -332,9 +332,7 @@ def test_info(api):
     assert r.version == mutalyzer.__version__
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize(
-    'references', [['AB026906.1', 'AL449423.14', 'NM_003002.2']], indirect=True)
+@with_references('AB026906.1', 'AL449423.14', 'NM_003002.2')
 def test_getcache(output, api):
     """
     Running the getCache method should give us the expected number of
@@ -393,8 +391,7 @@ def test_gettranscripts_with_versions(api):
         assert t in r.string
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_runmutalyzer(api):
     """
     Just a runMutalyzer test.
@@ -432,8 +429,7 @@ def test_runmutalyzer_reference_info_nm(api):
     assert r.molecule == 'n'
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_runmutalyzer_reference_info_nm_version(api):
     """
     Get reference info for an NM variant with version.
@@ -448,8 +444,7 @@ def test_runmutalyzer_reference_info_nm_version(api):
     assert r.molecule == 'n'
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['LRG_1']], indirect=True)
+@with_references('LRG_1')
 def test_runmutalyzer_reference_info_lrg(api):
     """
     Get reference info for an LRG variant.
@@ -461,8 +456,7 @@ def test_runmutalyzer_reference_info_lrg(api):
     assert r.molecule == 'g'
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_runmutalyzer_reference_info_ng(api):
     """
     Get reference info for an NG variant without version.
@@ -489,8 +483,7 @@ def test_runmutalyzer_reference_info_ng(api):
     assert r.molecule == 'g'
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_009105.1']], indirect=True)
+@with_references('NG_009105.1')
 def test_runmutalyzer_reference_info_ng_version(api):
     """
     Get reference info for an NG variant with version.
@@ -505,8 +498,7 @@ def test_runmutalyzer_reference_info_ng_version(api):
     assert r.molecule == 'g'
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_runmutalyzer_reference_info_gi(api):
     """
     Get reference info for a GI variant.
@@ -521,8 +513,7 @@ def test_runmutalyzer_reference_info_gi(api):
     assert r.molecule == 'g'
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_000143.3']], indirect=True)
+@with_references('NM_000143.3')
 def test_runmutalyzer_exons(api):
     """
     Exon table in runMutalyzer output.
@@ -544,10 +535,7 @@ def test_runmutalyzer_exons(api):
         assert (exon.gStart, exon.gStop, exon.cStart, exon.cStop) == expected_exon
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize(
-    'references', [['AB026906.1', 'NM_003002.2', 'AL449423.14']],
-    indirect=True)
+@with_references('AB026906.1', 'NM_003002.2', 'AL449423.14')
 def test_batchjob(api):
     """
     Submit a batch job.
diff --git a/tests/test_variantchecker.py b/tests/test_variantchecker.py
index f11590494f070f85220b411ea25242c12d725d4f..1f9cd1c294159e605b0cd3cf10179c557af50ce6 100644
--- a/tests/test_variantchecker.py
+++ b/tests/test_variantchecker.py
@@ -9,15 +9,14 @@ import pytest
 
 from mutalyzer.variantchecker import check_variant
 
+from fixtures import with_references
+
 
 # Todo: We had a test for checking a variant on a CONTIG RefSeq reference
 #   (NG_005990.1), but instead we should have separate tests for the retriever
 #   module, including a test for fetching a CONTIG RefSeq reference.
 
 
-pytestmark = pytest.mark.usefixtures('references')
-
-
 @pytest.fixture
 def checker(output):
     def check(description):
@@ -25,7 +24,7 @@ def checker(output):
     return check
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_in_frame(output, checker):
     """
     Simple in-frame deletion should give a simple description on protein
@@ -41,7 +40,7 @@ def test_deletion_in_frame(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_insertion_in_frame(output, checker):
     """
     Simple in-frame insertion should give a simple description on protein
@@ -57,7 +56,7 @@ def test_insertion_in_frame(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_insertion_list_in_frame(output, checker):
     """
     Simple in-frame insertion of a list should give a simple description
@@ -73,7 +72,7 @@ def test_insertion_list_in_frame(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_insertion_in_frame(output, checker):
     """
     Simple in-frame deletion/insertion should give a simple description on
@@ -89,7 +88,7 @@ def test_deletion_insertion_in_frame(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_insertion_list_in_frame(output, checker):
     """
     Simple in-frame deletion-insertion of a list should give a simple
@@ -105,7 +104,7 @@ def test_deletion_insertion_list_in_frame(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_insertion_in_frame_complete(output, checker):
     """
     Simple in-frame deletion/insertion should give a simple description on
@@ -121,7 +120,7 @@ def test_deletion_insertion_in_frame_complete(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_insertion_list_in_frame_complete(output, checker):
     """
     Simple in-frame deletion-insertion of a list should give a simple
@@ -138,7 +137,7 @@ def test_deletion_insertion_list_in_frame_complete(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_est_warning_nm_est(output, checker):
     """
     Warning for EST positioning on NM reference.
@@ -148,7 +147,7 @@ def test_est_warning_nm_est(output, checker):
     assert len(west) == 1
 
 
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_no_est_warning_nm_c(output, checker):
     """
     No EST warning for c. positioning on NM reference.
@@ -158,7 +157,7 @@ def test_no_est_warning_nm_c(output, checker):
     assert len(west) == 0
 
 
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_no_est_warning_nm_n(output, checker):
     """
     No EST warning for n. positioning on NM reference.
@@ -168,7 +167,7 @@ def test_no_est_warning_nm_n(output, checker):
     assert len(west) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_est_warning_ng_est(output, checker):
     """
     Warning for EST positioning on NG reference.
@@ -178,7 +177,7 @@ def test_est_warning_ng_est(output, checker):
     assert len(west) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_no_est_warning_ng_g(output, checker):
     """
     No EST warning for g. positioning on NG reference.
@@ -188,7 +187,7 @@ def test_no_est_warning_ng_g(output, checker):
     assert len(west) == 0
 
 
-@pytest.mark.parametrize('references', [['AA010203.1']], indirect=True)
+@with_references('AA010203.1')
 def test_no_est_warning_est_est(output, checker):
     """
     No warning for EST positioning on EST reference.
@@ -198,7 +197,7 @@ def test_no_est_warning_est_est(output, checker):
     assert len(west) == 0
 
 
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_roll(output, checker):
     """
     Just a variant where we should roll.
@@ -208,7 +207,7 @@ def test_roll(output, checker):
     assert len(wroll) > 0
 
 
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_no_roll(output, checker):
     """
     Just a variant where we cannot roll.
@@ -218,7 +217,7 @@ def test_no_roll(output, checker):
     assert len(wroll) == 0
 
 
-@pytest.mark.parametrize('references', [['NM_000088.3']], indirect=True)
+@with_references('NM_000088.3')
 def test_no_roll_splice(output, checker):
     """
     Here we can roll but should not, because it is over a splice site.
@@ -230,7 +229,7 @@ def test_no_roll_splice(output, checker):
     assert len(wroll) == 0
 
 
-@pytest.mark.parametrize('references', [['NM_000088.3']], indirect=True)
+@with_references('NM_000088.3')
 def test_partial_roll_splice(output, checker):
     """
     Here we can roll two positions, but should roll only one because
@@ -243,7 +242,7 @@ def test_partial_roll_splice(output, checker):
     assert len(wroll) > 0
 
 
-@pytest.mark.parametrize('references', [['NM_000088.3']], indirect=True)
+@with_references('NM_000088.3')
 def test_roll_after_splice(output, checker):
     """
     Here we can roll and should, we stay in the same exon.
@@ -253,7 +252,7 @@ def test_roll_after_splice(output, checker):
     assert len(wroll) > 0
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_roll_both_ins(output, checker):
     """
     Insertion that rolls should not use the same inserted sequence in
@@ -288,7 +287,7 @@ def test_roll_both_ins(output, checker):
     assert len(output.getMessagesWithErrorCode('WROLLFORWARD')) == 1
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_roll_reverse_ins(output, checker):
     """
     Insertion that rolls on the reverse strand should not use the same
@@ -300,7 +299,7 @@ def test_roll_reverse_ins(output, checker):
     assert len(output.getMessagesWithErrorCode('WROLLFORWARD')) == 0
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_roll_message_forward(output, checker):
     """
     Roll warning message should only be shown for currently selected
@@ -311,7 +310,7 @@ def test_roll_message_forward(output, checker):
     assert len(output.getMessagesWithErrorCode('WROLLREVERSE')) == 0
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_roll_message_reverse(output, checker):
     """
     Roll warning message should only be shown for currently selected
@@ -322,7 +321,7 @@ def test_roll_message_reverse(output, checker):
     assert len(output.getMessagesWithErrorCode('WROLLREVERSE')) == 1
 
 
-@pytest.mark.parametrize('references', [['NM_000143.3']], indirect=True)
+@with_references('NM_000143.3')
 def test_ins_cds_start(output, checker):
     """
     Insertion on CDS start boundary should not be included in CDS.
@@ -332,7 +331,7 @@ def test_ins_cds_start(output, checker):
     # Todo: Is this a good test?
 
 
-@pytest.mark.parametrize('references', [['NM_000143.3']], indirect=True)
+@with_references('NM_000143.3')
 def test_ins_cds_start_after(output, checker):
     """
     Insertion after CDS start boundary should be included in CDS.
@@ -342,7 +341,7 @@ def test_ins_cds_start_after(output, checker):
     # Todo: Is this a good test?
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_splice_site(output, checker):
     """
     Deletion hitting one splice site should not do a protein prediction.
@@ -355,7 +354,7 @@ def test_del_splice_site(output, checker):
     assert not output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exon(output, checker):
     """
     Deletion of an entire exon should be possible.
@@ -368,7 +367,7 @@ def test_del_exon(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exon_exact(output, checker):
     """
     Deletion of exactly an exon should be possible.
@@ -381,7 +380,7 @@ def test_del_exon_exact(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exon_in_frame(output, checker):
     """
     Deletion of an entire exon with length a triplicate should give a
@@ -400,7 +399,7 @@ def test_del_exon_in_frame(output, checker):
     # Todo: assert that protein products indeed have only this difference.
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exons(output, checker):
     """
     Deletion of two entire exons should be possible.
@@ -413,7 +412,7 @@ def test_del_exons(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_intron(output, checker):
     """
     Deletion of an entire intron should be possible (fusion of remaining
@@ -427,7 +426,7 @@ def test_del_intron(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_intron_exact(output, checker):
     """
     Deletion of exactly an intron should be possible (fusion of flanking
@@ -444,7 +443,7 @@ def test_del_intron_exact(output, checker):
     assert not output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_intron_in_frame(output, checker):
     """
     Deletion of an entire intron should be possible (fusion of remaining
@@ -459,7 +458,7 @@ def test_del_intron_in_frame(output, checker):
     # Todo: assert that protein products indeed have only this difference.
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exon_unknown_offsets(output, checker):
     """
     Deletion of an entire exon with unknown offsets should be possible.
@@ -480,7 +479,7 @@ def test_del_exon_unknown_offsets(output, checker):
     # other transcripts?
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exon_unknown_offsets_in_frame(output, checker):
     """
     Deletion of an entire exon with unknown offsets and length a
@@ -504,7 +503,7 @@ def test_del_exon_unknown_offsets_in_frame(output, checker):
     # other transcripts?
 
 
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_del_exon_unknown_offsets_composed(output, checker):
     """
     Deletion of an entire exon with unknown offsets and another composed
@@ -525,7 +524,7 @@ def test_del_exon_unknown_offsets_composed(output, checker):
     # other transcripts?
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_del_exon_unknown_offsets_reverse(output, checker):
     """
     Deletion of an entire exon with unknown offsets should be possible,
@@ -546,7 +545,7 @@ def test_del_exon_unknown_offsets_reverse(output, checker):
     # other transcripts?
 
 
-@pytest.mark.parametrize('references', [['NM_000143.3']], indirect=True)
+@with_references('NM_000143.3')
 def test_del_exon_transcript_reference(output, checker):
     """
     Deletion of entire exon on a transcript reference should remove the
@@ -563,7 +562,7 @@ def test_del_exon_transcript_reference(output, checker):
     assert output.getOutput('newProtein')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq(output, checker):
     """
     Insertion of a sequence.
@@ -574,7 +573,7 @@ def test_ins_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_012337.1']], indirect=True)
+@with_references('NG_012337.1')
 def test_ins_seq_reverse(output, checker):
     """
     Insertion of a sequence on reverse strand.
@@ -585,7 +584,7 @@ def test_ins_seq_reverse(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range(output, checker):
     """
     Insertion of a range.
@@ -597,7 +596,7 @@ def test_ins_range(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_inv(output, checker):
     """
     Insertion of an inverse range.
@@ -609,7 +608,7 @@ def test_ins_range_inv(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_list(output, checker):
     """
     Insertion of a sequence as a list.
@@ -620,7 +619,7 @@ def test_ins_seq_list(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_012337.1']], indirect=True)
+@with_references('NG_012337.1')
 def test_ins_seq_list_reverse(output, checker):
     """
     Insertion of a sequence as a list on reverse strand.
@@ -631,7 +630,7 @@ def test_ins_seq_list_reverse(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_list(output, checker):
     """
     Insertion of a range as a list.
@@ -643,7 +642,7 @@ def test_ins_range_list(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_inv_list(output, checker):
     """
     Insertion of an inverse range as a list.
@@ -655,7 +654,7 @@ def test_ins_range_inv_list(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_seq(output, checker):
     """
     Insertion of two sequences.
@@ -666,7 +665,7 @@ def test_ins_seq_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_012337.1']], indirect=True)
+@with_references('NG_012337.1')
 def test_ins_seq_seq_reverse(output, checker):
     """
     Insertion of two sequences on reverse strand.
@@ -677,7 +676,7 @@ def test_ins_seq_seq_reverse(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_range(output, checker):
     """
     Insertion of two ranges.
@@ -689,7 +688,7 @@ def test_ins_range_range(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_range_inv(output, checker):
     """
     Insertion of a range and an inverse range.
@@ -701,7 +700,7 @@ def test_ins_range_range_inv(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_range(output, checker):
     """
     Insertion of a sequence and a range.
@@ -712,7 +711,7 @@ def test_ins_seq_range(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_range_inv(output, checker):
     """
     Insertion of a sequence and an inverse range.
@@ -723,7 +722,7 @@ def test_ins_seq_range_inv(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_seq(output, checker):
     """
     Insertion of a range and a sequence.
@@ -734,7 +733,7 @@ def test_ins_range_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_inv_seq(output, checker):
     """
     Insertion of an inverse range and a sequence.
@@ -745,7 +744,7 @@ def test_ins_range_inv_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_coding(output, checker):
     """
     Insertion of a sequence (coding).
@@ -756,7 +755,7 @@ def test_ins_seq_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_list_coding(output, checker):
     """
     Insertion of a sequence as a list (coding).
@@ -767,7 +766,7 @@ def test_ins_seq_list_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_seq_seq_coding(output, checker):
     """
     Insertion of two sequences (coding).
@@ -778,7 +777,7 @@ def test_ins_seq_seq_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_coding(output, checker):
     """
     Insertion of a range (coding).
@@ -787,7 +786,7 @@ def test_ins_range_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_inv_coding(output, checker):
     """
     Insertion of an inverse range (coding).
@@ -796,7 +795,7 @@ def test_ins_range_inv_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_list_coding(output, checker):
     """
     Insertion of a range as a list (coding).
@@ -805,7 +804,7 @@ def test_ins_range_list_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_ins_range_inv_list_coding(output, checker):
     """
     Insertion of an inverse range as a list (coding).
@@ -814,7 +813,7 @@ def test_ins_range_inv_list_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq(output, checker):
     """
     Insertion-deletion of a sequence.
@@ -825,7 +824,7 @@ def test_delins_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range(output, checker):
     """
     Insertion-deletion of a range.
@@ -837,7 +836,7 @@ def test_delins_range(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_inv(output, checker):
     """
     Insertion-deletion of an inverse range.
@@ -849,7 +848,7 @@ def test_delins_range_inv(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_list(output, checker):
     """
     Insertion-deletion of a sequence as a list.
@@ -860,7 +859,7 @@ def test_delins_seq_list(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_list(output, checker):
     """
     Insertion-deletion of a range as a list.
@@ -872,7 +871,7 @@ def test_delins_range_list(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_inv_list(output, checker):
     """
     Insertion-deletion of an inverse range as a list.
@@ -884,7 +883,7 @@ def test_delins_range_inv_list(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_seq(output, checker):
     """
     Insertion-deletion of two sequences.
@@ -895,7 +894,7 @@ def test_delins_seq_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_range(output, checker):
     """
     Insertion-deletion of two ranges.
@@ -907,7 +906,7 @@ def test_delins_range_range(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_inv_range(output, checker):
     """
     Insertion-deletion of an inverse range and a range.
@@ -921,7 +920,7 @@ def test_delins_range_inv_range(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 0
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_range(output, checker):
     """
     Insertion-deletion of a sequence and a range.
@@ -932,7 +931,7 @@ def test_delins_seq_range(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_range_inv(output, checker):
     """
     Insertion-deletion of a sequence and an inverse range.
@@ -945,7 +944,7 @@ def test_delins_seq_range_inv(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_seq(output, checker):
     """
     Insertion-deletion of a range and a sequence.
@@ -956,7 +955,7 @@ def test_delins_range_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_inv_seq(output, checker):
     """
     Insertion-deletion of an inverse range and a sequence.
@@ -969,7 +968,7 @@ def test_delins_range_inv_seq(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_coding(output, checker):
     """
     Insertion-deletion of a sequence (coding).
@@ -980,7 +979,7 @@ def test_delins_seq_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_list_coding(output, checker):
     """
     Insertion-deletion of a sequence as a list (coding).
@@ -991,7 +990,7 @@ def test_delins_seq_list_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_seq_seq_coding(output, checker):
     """
     Insertion-deletion of two sequences (coding).
@@ -1002,7 +1001,7 @@ def test_delins_seq_seq_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_coding(output, checker):
     """
     Insertion-deletion of a range (coding).
@@ -1011,7 +1010,7 @@ def test_delins_range_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_inv_coding(output, checker):
     """
     Insertion-deletion of an inverse range (coding).
@@ -1020,7 +1019,7 @@ def test_delins_range_inv_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_list_coding(output, checker):
     """
     Insertion-deletion of a range as a list (coding).
@@ -1029,7 +1028,7 @@ def test_delins_range_list_coding(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_delins_range_inv_list_coding(output, checker):
     """
     Insertion-deletion of an inverse range as a list (coding).
@@ -1047,7 +1046,7 @@ def test_no_reference(output, checker):
 
 
 @pytest.mark.usefixtures('hg19_transcript_mappings')
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_chromosomal_positions(output, checker):
     """
     Variants on transcripts in c. notation should have chromosomal positions
@@ -1057,7 +1056,7 @@ def test_chromosomal_positions(output, checker):
     assert output.getIndexedOutput('rawVariantsChromosomal', 0) == ('chr11', '+', [('274G>T', (111959695, 111959695))])
 
 
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_ex_notation(output, checker):
     """
     Variant description using EX notation should not crash but deletion of
@@ -1067,7 +1066,7 @@ def test_ex_notation(output, checker):
     assert len(output.getMessagesWithErrorCode('IDELSPLICE')) == 1
 
 
-@pytest.mark.parametrize('references', [['LRG_1']], indirect=True)
+@with_references('LRG_1')
 def test_lrg_reference(output, checker):
     """
     We should be able to use LRG reference sequence without error.
@@ -1078,7 +1077,7 @@ def test_lrg_reference(output, checker):
     assert output.getIndexedOutput('genomicDescription', 0) == 'LRG_1:g.6855G>T'
 
 
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_gi_reference_plain(output, checker):
     """
     Test reference sequence notation with GI number.
@@ -1091,7 +1090,7 @@ def test_gi_reference_plain(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_gi_reference_prefix(output, checker):
     """
     Test reference sequence notation with GI number and prefix.
@@ -1104,7 +1103,7 @@ def test_gi_reference_prefix(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_gi_reference_prefix_colon(output, checker):
     """
     Test reference sequence notation with GI number and prefix with colon.
@@ -1117,7 +1116,7 @@ def test_gi_reference_prefix_colon(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_nop_nm(output, checker):
     """
     Variant on NM without effect should be described as '='.
@@ -1130,7 +1129,7 @@ def test_nop_nm(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['DMD']], indirect=True)
+@with_references('DMD')
 def test_nop_ud(output, references, checker):
     """
     Variant on UD without effect should be described as '='.
@@ -1144,7 +1143,7 @@ def test_nop_ud(output, references, checker):
     assert ud + '(DMD_v001):c.=' in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['DPYD']], indirect=True)
+@with_references('DPYD')
 def test_ud_reverse_sequence(output, references, checker):
     """
     Variant on UD from reverse strand should have reverse complement
@@ -1159,7 +1158,7 @@ def test_ud_reverse_sequence(output, references, checker):
     assert ud + '(DPYD_v001):c.85C>T' in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['MARK1']], indirect=True)
+@with_references('MARK1')
 def test_ud_forward_sequence(output, references, checker):
     """
     Variant on UD from forward strand should have forward sequence.
@@ -1173,7 +1172,7 @@ def test_ud_forward_sequence(output, references, checker):
     assert ud + '(MARK1_v001):c.400T>C' in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['chr9_reverse']], indirect=True)
+@with_references('chr9_reverse')
 def test_ud_reverse_range(output, references, checker):
     """
     Variant on UD from reverse strand should have reversed range
@@ -1188,7 +1187,7 @@ def test_ud_reverse_range(output, references, checker):
     assert output.getIndexedOutput('genomicDescription', 0) == ud + ':g.10624_78132del'
 
 
-@pytest.mark.parametrize('references', [['MARK1']], indirect=True)
+@with_references('MARK1')
 def test_ud_forward_range(output, references, checker):
     """
     Variant on UD from forward strand should have forward range positions.
@@ -1201,7 +1200,7 @@ def test_ud_forward_range(output, references, checker):
     assert output.getIndexedOutput('genomicDescription', 0) == ud + ':g.76614_76629del'
 
 
-@pytest.mark.parametrize('references', [['chr9_reverse']], indirect=True)
+@with_references('chr9_reverse')
 def test_ud_reverse_del_length(output, references, checker):
     """
     Variant on UD from reverse strand should have reversed range
@@ -1217,7 +1216,7 @@ def test_ud_reverse_del_length(output, references, checker):
     assert output.getIndexedOutput('genomicDescription', 0) == ud + ':g.10624_78132del'
 
 
-@pytest.mark.parametrize('references', [['DPYD']], indirect=True)
+@with_references('DPYD')
 def test_ud_reverse_roll(output, references, checker):
     """
     Variant on UD from reverse strand should roll the oposite direction.
@@ -1238,7 +1237,7 @@ def test_ud_reverse_roll(output, references, checker):
     assert ud + '(DPYD_v001):c.105del' in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['MARK1']], indirect=True)
+@with_references('MARK1')
 def test_ud_forward_roll(output, references, checker):
     """
     Variant on UD from forward strand should roll the same.
@@ -1259,7 +1258,7 @@ def test_ud_forward_roll(output, references, checker):
     assert ud + '(MARK1_v001):c.401del' in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_with_sequence_forward_genomic(output, checker):
     """
     Specify the deleted sequence in a deletion.
@@ -1270,7 +1269,7 @@ def test_deletion_with_sequence_forward_genomic(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_with_length_forward_genomic(output, checker):
     """
     Specify the deleted sequence length in a deletion.
@@ -1281,7 +1280,7 @@ def test_deletion_with_length_forward_genomic(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_with_sequence_reverse_coding(output, checker):
     """
     Specify the deleted sequence in a deletion on the reverse strand.
@@ -1292,7 +1291,7 @@ def test_deletion_with_sequence_reverse_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['AL449423.14']], indirect=True)
+@with_references('AL449423.14')
 def test_deletion_with_length_reverse_coding(output, checker):
     """
     Specify the deleted sequence length in a deletion on the reverse strand.
@@ -1303,7 +1302,7 @@ def test_deletion_with_length_reverse_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_deletion_with_sequence_reverse_ng_coding(output, checker):
     """
     Specify the deleted sequence in a deletion on the reverse strand
@@ -1315,7 +1314,7 @@ def test_deletion_with_sequence_reverse_ng_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_deletion_with_length_reverse_ng_coding(output, checker):
     """
     Specify the deleted sequence length in a deletion on the reverse strand
@@ -1327,7 +1326,7 @@ def test_deletion_with_length_reverse_ng_coding(output, checker):
            in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['AB026906.1']], indirect=True)
+@with_references('AB026906.1')
 def test_inversion(output, checker):
     """
     Inversion variant.
@@ -1338,7 +1337,7 @@ def test_inversion(output, checker):
         in output.getOutput('descriptions')
 
 
-@pytest.mark.parametrize('references', [['NM_000193.2']], indirect=True)
+@with_references('NM_000193.2')
 def test_delins_with_length(output, checker):
     """
     Delins with explicit length of deleted sequence (bug #108).
@@ -1347,7 +1346,7 @@ def test_delins_with_length(output, checker):
     assert 'NM_000193.2(SHH_i001):p.(Lys38Serfs*2)' in output.getOutput('protDescriptions')
 
 
-@pytest.mark.parametrize('references', [['NG_009105.1']], indirect=True)
+@with_references('NG_009105.1')
 def test_protein_level_description(output, checker):
     """
     Currently protein level descriptions are not implemented.
@@ -1356,7 +1355,7 @@ def test_protein_level_description(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['NP_064445.1']], indirect=True)
+@with_references('NP_064445.1')
 def test_protein_reference(output, checker):
     """
     Currently protein references are not implemented.
@@ -1365,7 +1364,7 @@ def test_protein_reference(output, checker):
     assert len(output.getMessagesWithErrorCode('ENOTIMPLEMENTED')) == 1
 
 
-@pytest.mark.parametrize('references', [['AF230870.1']], indirect=True)
+@with_references('AF230870.1')
 def test_wnomrna_other(output, checker):
     """
     Warning for no mRNA field on other than currently selected transcript
@@ -1377,7 +1376,7 @@ def test_wnomrna_other(output, checker):
     assert len(wnomrna_other) == 1
 
 
-@pytest.mark.parametrize('references', [['AF230870.1']], indirect=True)
+@with_references('AF230870.1')
 def test_wnomrna(output, checker):
     """
     Warning for no mRNA field on currently selected transcript should give
@@ -1391,7 +1390,7 @@ def test_wnomrna(output, checker):
     assert len(wnomrna_other) == 1
 
 
-@pytest.mark.parametrize('references', [['L41870.1']], indirect=True)
+@with_references('L41870.1')
 def test_mrna_ref_adjacent_exons_warn(output, checker):
     """
     Warning for mRNA reference where exons are not adjacent.
@@ -1403,7 +1402,7 @@ def test_mrna_ref_adjacent_exons_warn(output, checker):
     assert len(w_exon_annotation) == 1
 
 
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@with_references('NM_003002.2')
 def test_mrna_ref_adjacent_exons_no_warn(output, checker):
     """
     No warning for mRNA reference where exons are adjacent.
@@ -1413,7 +1412,7 @@ def test_mrna_ref_adjacent_exons_no_warn(output, checker):
     assert len(w_exon_annotation) == 0
 
 
-@pytest.mark.parametrize('references', [['NM_001199.3']], indirect=True)
+@with_references('NM_001199.3')
 def test_fs_no_stop(output, checker):
     """
     Frame shift yielding no stop codon should be described with
@@ -1425,7 +1424,7 @@ def test_fs_no_stop(output, checker):
     assert 'NM_001199.3(BMP1_i001):p.(Gln730Profs*?)' in output.getOutput('protDescriptions')
 
 
-@pytest.mark.parametrize('references', [['NM_000193.2']], indirect=True)
+@with_references('NM_000193.2')
 def test_ext_no_stop(output, checker):
     """
     Extension yielding no stop codon should be described with
@@ -1437,7 +1436,7 @@ def test_ext_no_stop(output, checker):
     assert 'NM_000193.2(SHH_i001):p.(*463Serext*?)' in output.getOutput('protDescriptions')
 
 
-@pytest.mark.parametrize('references', [['NM_000193.2']], indirect=True)
+@with_references('NM_000193.2')
 def test_fs_ext_no_stop(output, checker):
     """
     Extension yielding no stop codon should be described with
@@ -1449,7 +1448,7 @@ def test_fs_ext_no_stop(output, checker):
     assert 'NM_000193.2(SHH_i001):p.(*463Cysext*?)' in output.getOutput('protDescriptions')
 
 
-@pytest.mark.parametrize('references', [['AB026906.1']], indirect=True)
+@with_references('AB026906.1')
 def test_synonymous_p_is(output, checker):
     """
     Synonymous mutation should yield a p.(=) description.
@@ -1459,7 +1458,7 @@ def test_synonymous_p_is(output, checker):
     assert not output.getOutput('newProteinFancy')
 
 
-@pytest.mark.parametrize('references', [['NM_024426.4']], indirect=True)
+@with_references('NM_024426.4')
 def test_synonymous_p_is_alt_start(output, checker):
     """
     Synonymous mutation should yield a p.(=) description, also with an
@@ -1476,7 +1475,7 @@ def test_synonymous_p_is_alt_start(output, checker):
     assert not output.getOutput('altProteinFancy')
 
 
-@pytest.mark.parametrize('references', [['AB026906.1']], indirect=True)
+@with_references('AB026906.1')
 def test_start_codon(output, checker):
     """
     Mutation of start codon should yield a p.? description.
@@ -1491,7 +1490,7 @@ def test_start_codon(output, checker):
     assert not output.getOutput('altStart')
 
 
-@pytest.mark.parametrize('references', [['NM_024426.4']], indirect=True)
+@with_references('NM_024426.4')
 def test_start_codon_alt_start(output, checker):
     """
     Mutation of start codon should yield a p.? description, also with an
@@ -1507,7 +1506,7 @@ def test_start_codon_alt_start(output, checker):
     assert not output.getOutput('altStart')
 
 
-@pytest.mark.parametrize('references', [['AB026906.1']], indirect=True)
+@with_references('AB026906.1')
 def test_start_codon_yield_start_p_is(output, checker):
     """
     Silent mutation creating new start codon should yield a p.?
@@ -1526,7 +1525,7 @@ def test_start_codon_yield_start_p_is(output, checker):
     assert not output.getOutput('altProteinFancy')
 
 
-@pytest.mark.parametrize('references', [['NM_024426.4']], indirect=True)
+@with_references('NM_024426.4')
 def test_start_codon_alt_start_yield_start_p_is(output, checker):
     """
     Silent mutation creating new start codon should yield a p.?
@@ -1545,7 +1544,7 @@ def test_start_codon_alt_start_yield_start_p_is(output, checker):
     assert not output.getOutput('altProteinFancy')
 
 
-@pytest.mark.parametrize('references', [['AB026906.1']], indirect=True)
+@with_references('AB026906.1')
 def test_start_codon_yield_start(output, checker):
     """
     Mutation creating new start codon should yield a p.? description. The
@@ -1562,7 +1561,7 @@ def test_start_codon_yield_start(output, checker):
     assert output.getOutput('altProtein')[0].startswith('M')
 
 
-@pytest.mark.parametrize('references', [['NM_024426.4']], indirect=True)
+@with_references('NM_024426.4')
 def test_start_codon_alt_start_yield_start(output, checker):
     """
     Mutation creating new start codon should yield a p.? description, also
diff --git a/tests/test_website.py b/tests/test_website.py
index 57d085c2240c19d7ef9f1b0365b606f7ae00e5d0..b6b0b2f973f39748dd461782c47e048da44e6043 100644
--- a/tests/test_website.py
+++ b/tests/test_website.py
@@ -18,6 +18,8 @@ from mutalyzer import announce, Scheduler
 from mutalyzer.db.models import BatchJob
 from mutalyzer.website import create_app
 
+from fixtures import with_references
+
 
 # TODO: Tests for /upload.
 
@@ -125,9 +127,7 @@ def test_description_extractor_raw_fastq(website):
     assert '[5_6insTT;17del;26A>C;35dup]' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize(
-    'references', [['NM_004006.1', 'NM_004006.2']], indirect=True)
+@with_references('NM_004006.1', 'NM_004006.2')
 def test_description_extractor_refseq(website):
     """
     Submit two accession numbers to the variant description extractor.
@@ -247,8 +247,7 @@ def test_checksyntax_invalid(website):
     assert 'The "^" indicates the position where the error occurred' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_check_valid(website):
     """
     Submit the name checker form with a valid variant.
@@ -273,8 +272,7 @@ def test_check_invalid(website):
     assert 'The "^" indicates the position where the error occurred' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NP_064445.1']], indirect=True)
+@with_references('NP_064445.1')
 def test_check_protein_reference(website):
     """
     Submit the name checker form with a protein reference sequence (not
@@ -287,8 +285,7 @@ def test_check_protein_reference(website):
     assert 'Protein reference sequences are not supported' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_check_noninteractive(website):
     """
     Submit the name checker form non-interactively.
@@ -304,8 +301,7 @@ def test_check_noninteractive(website):
     assert 'Raw variant 1: deletion of 1' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_012772.1']], indirect=True)
+@with_references('NG_012772.1')
 def test_check_interactive_links(website):
     """
     Submitting interactively should have links to transcripts also
@@ -427,10 +423,7 @@ def _batch(website, job_type='name-checker', assembly_name_or_alias=None,
     return r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize(
-    'references', [['AB026906.1', 'NM_003002.2', 'AL449423.14']],
-    indirect=True)
+@with_references('AB026906.1', 'NM_003002.2', 'AL449423.14')
 def test_batch_namechecker(website):
     """
     Submit the batch name checker form.
@@ -610,8 +603,7 @@ def test_batch_syntaxchecker_oldstyle(website):
            header='Input\tStatus')
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['AB026906.1']], indirect=True)
+@with_references('AB026906.1')
 def test_batch_namechecker_restriction_sites(website):
     """
     Submit the batch name checker form and see if restriction site effects
@@ -703,8 +695,7 @@ def test_annotated_soap_api(website):
     assert 'Web Service: Mutalyzer' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_012337.1']], indirect=True)
+@with_references('NG_012337.1')
 def test_getgs(website):
     """
     Test the /getGS interface used by LOVD2.
@@ -721,8 +712,7 @@ def test_getgs(website):
     assert '<input' not in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_012337.1']], indirect=True)
+@with_references('NG_012337.1')
 def test_getgs_coding_multiple_transcripts(website):
     """
     Test the /getGS interface on a coding description and genomic
@@ -737,8 +727,7 @@ def test_getgs_coding_multiple_transcripts(website):
     assert 'description=NG_012337.1' in r.location
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NG_008939.1']], indirect=True)
+@with_references('NG_008939.1')
 def test_getgs_variant_error(website):
     """
     Test the /getGS interface on a variant description with an error.
@@ -861,8 +850,7 @@ def test_upload_local_file_invalid(website):
     assert 'The file could not be parsed.' in r.data
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_reference(website):
     """
     Test if reference files are cached.
@@ -878,8 +866,7 @@ def test_reference(website):
     assert r.data == bz2.BZ2File(path).read()
 
 
-@pytest.mark.usefixtures('references')
-@pytest.mark.parametrize('references', [['NM_002001.2']], indirect=True)
+@with_references('NM_002001.2')
 def test_reference_head(website):
     """
     Test if reference files are cached, by issuing a HEAD request.
@@ -901,8 +888,8 @@ def test_reference_head_none(website):
     assert r.status_code == 404
 
 
-@pytest.mark.usefixtures('references', 'hg19_transcript_mappings')
-@pytest.mark.parametrize('references', [['NM_003002.2']], indirect=True)
+@pytest.mark.usefixtures('hg19_transcript_mappings')
+@with_references('NM_003002.2')
 def test_bed(website):
     """
     BED track for variant.
@@ -913,8 +900,8 @@ def test_bed(website):
     assert '\t'.join(['chr11', '111959694', '111959695', '274G>T', '0', '+']) in r.data
 
 
-@pytest.mark.usefixtures('references', 'hg19_transcript_mappings')
-@pytest.mark.parametrize('references', [['NM_000132.3']], indirect=True)
+@pytest.mark.usefixtures('hg19_transcript_mappings')
+@with_references('NM_000132.3')
 def test_bed_reverse(website):
     """
     BED track for variant on reverse strand.