Repository: pydicom/pydicom

Issue:
JSON code improvements
Keeping a checklist of some thoughts on JSON code refactoring/improvements

- [ ] move data element to_json code to DataElement class
- [ ] make sure constants and code that is not class-specific are moved to json_rep.py
- [x] move all tests to test_json.py

PRs gratefully accepted ;-)

Discussion:

Patch:
diff --git a/doc/whatsnew/v1.4.0.rst b/doc/whatsnew/v1.4.0.rst
index 46b56f74a..ca25f8ed8 100644
--- a/doc/whatsnew/v1.4.0.rst
+++ b/doc/whatsnew/v1.4.0.rst
@@ -7,3 +7,7 @@ Changelog
 Fixes
 .....
 * Fixed handling of binary values in json encoding (:issue:`887`)
+* Prevent exception if assigning `None` to UI element (:issue:`894`)
+* Fixed print output for numeric multi-value elements (:issue:`892`)
+* Fixed testing PN values for truthiness (:issue:`891`)
+* Fixed handling of known tags with VR UN (:issue:`899`)
diff --git a/pydicom/config.py b/pydicom/config.py
index ae9c8bdf1..d3f589110 100644
--- a/pydicom/config.py
+++ b/pydicom/config.py
@@ -62,10 +62,7 @@ and datetime.time respectively. Default: False
 
 # Logging system and debug function to change logging level
 logger = logging.getLogger('pydicom')
-handler = logging.StreamHandler()
-formatter = logging.Formatter("%(message)s")
-handler.setFormatter(formatter)
-logger.addHandler(handler)
+logger.addHandler(logging.NullHandler())
 
 
 import pydicom.pixel_data_handlers.numpy_handler as np_handler  # noqa
@@ -110,16 +107,29 @@ syntax, then this fact is announced in a NotImplementedError exception.
 """
 
 
-def debug(debug_on=True):
-    """Turn debugging of DICOM file reading and writing on or off.
+def debug(debug_on=True, default_handler=True):
+    """Turn on/off debugging of DICOM file reading and writing.
+
     When debugging is on, file location and details about the
     elements read at that location are logged to the 'pydicom'
     logger using python's logging module.
 
-    :param debug_on: True (default) to turn on debugging,
-    False to turn off.
+    Parameters
+    ----------
+    debug_on : bool, optional
+        If True (default) then turn on debugging, False to turn off.
+    default_handler : bool, optional
+        If True (default) then use ``logging.StreamHandler()`` as the handler
+        for log messages.
     """
     global logger, debugging
+
+    if default_handler:
+        handler = logging.StreamHandler()
+        formatter = logging.Formatter("%(message)s")
+        handler.setFormatter(formatter)
+        logger.addHandler(handler)
+
     if debug_on:
         logger.setLevel(logging.DEBUG)
         debugging = True
@@ -129,4 +139,4 @@ def debug(debug_on=True):
 
 
 # force level=WARNING, in case logging default is set differently (issue 103)
-debug(False)
+debug(False, False)
diff --git a/pydicom/dataelem.py b/pydicom/dataelem.py
index 56d05bee6..226240f07 100644
--- a/pydicom/dataelem.py
+++ b/pydicom/dataelem.py
@@ -10,6 +10,7 @@ A DataElement has a tag,
 from __future__ import absolute_import
 
 import base64
+import json
 import warnings
 from collections import namedtuple
 
@@ -165,6 +166,17 @@ class DataElement(object):
         if not isinstance(tag, BaseTag):
             tag = Tag(tag)
         self.tag = tag
+
+        # a known tag shall only have the VR 'UN' if it has a length that
+        # exceeds the size that can be encoded in 16 bit - all other cases
+        # can be seen as an encoding error and can be corrected
+        if VR == 'UN' and (is_undefined_length or value is None or
+                           len(value) < 0xffff):
+            try:
+                VR = dictionary_VR(tag)
+            except KeyError:
+                pass
+
         self.VR = VR  # Note!: you must set VR before setting value
         if already_converted:
             self._value = value
@@ -181,6 +193,8 @@ class DataElement(object):
 
         Parameters
         ----------
+        dataset_class: Dataset derived class
+            class used to create sequence items
         tag: pydicom.tag.Tag
             data element tag
         vr: str
@@ -287,21 +301,116 @@ class DataElement(object):
             logger.warning('missing value for data element "{}"'.format(tag))
             elem_value = ''
 
-        elem_value = jsonrep._convert_to_python_number(elem_value, vr)
+        elem_value = jsonrep.convert_to_python_number(elem_value, vr)
 
         try:
             if compat.in_py2 and vr == "PN":
-
                 elem_value = PersonNameUnicode(elem_value, 'UTF8')
             return DataElement(tag=tag, value=elem_value, VR=vr)
         except Exception:
-            raise
             raise ValueError(
                 'Data element "{}" could not be loaded from JSON: {}'.format(
                     tag, elem_value
                     )
             )
 
+    def to_json(self, bulk_data_element_handler,
+                bulk_data_threshold, dump_handler):
+        """Converts a DataElement to JSON representation.
+
+        Parameters
+        ----------
+        bulk_data_element_handler: Union[Callable, None]
+            callable that accepts a bulk data element and returns the
+            "BulkDataURI" for retrieving the value of the data element
+            via DICOMweb WADO-RS
+        bulk_data_threshold: int
+            size of base64 encoded data element above which a value will be
+            provided in form of a "BulkDataURI" rather than "InlineBinary"
+
+        Returns
+        -------
+        dict
+            mapping representing a JSON encoded data element
+
+        Raises
+        ------
+        TypeError
+            when size of encoded data element exceeds `bulk_data_threshold`
+            but `bulk_data_element_handler` is ``None`` and hence not callable
+
+        """
+        # TODO: Determine whether more VRs need to be converted to strings
+        _VRs_TO_QUOTE = ['AT', ]
+        json_element = {'vr': self.VR, }
+        if self.VR in jsonrep.BINARY_VR_VALUES:
+            if self.value is not None:
+                binary_value = self.value
+                encoded_value = base64.b64encode(binary_value).decode('utf-8')
+                if len(encoded_value) > bulk_data_threshold:
+                    if bulk_data_element_handler is None:
+                        raise TypeError(
+                            'No bulk data element handler provided to '
+                            'generate URL for value of data element "{}".'
+                            .format(self.name)
+                        )
+                    json_element['BulkDataURI'] = bulk_data_element_handler(
+                        self
+                    )
+                else:
+                    logger.info(
+                        'encode bulk data element "{}" inline'.format(
+                            self.name
+                        )
+                    )
+                    json_element['InlineBinary'] = encoded_value
+        elif self.VR == 'SQ':
+            # recursive call to co-routine to format sequence contents
+            value = [
+                json.loads(e.to_json(
+                    bulk_data_element_handler=bulk_data_element_handler,
+                    bulk_data_threshold=bulk_data_threshold,
+                    dump_handler=dump_handler
+                ))
+                for e in self
+            ]
+            json_element['Value'] = value
+        elif self.VR == 'PN':
+            elem_value = self.value
+            if elem_value is not None:
+                if compat.in_py2:
+                    elem_value = PersonNameUnicode(elem_value, 'UTF8')
+                if len(elem_value.components) > 2:
+                    json_element['Value'] = [
+                        {'Phonetic': elem_value.components[2], },
+                    ]
+                elif len(elem_value.components) > 1:
+                    json_element['Value'] = [
+                        {'Ideographic': elem_value.components[1], },
+                    ]
+                else:
+                    json_element['Value'] = [
+                        {'Alphabetic': elem_value.components[0], },
+                    ]
+        else:
+            if self.value is not None:
+                is_multivalue = isinstance(self.value, MultiValue)
+                if self.VM > 1 or is_multivalue:
+                    value = self.value
+                else:
+                    value = [self.value]
+                # ensure it's a list and not another iterable
+                # (e.g. tuple), which would not be JSON serializable
+                if self.VR in _VRs_TO_QUOTE:
+                    json_element['Value'] = [str(v) for v in value]
+                else:
+                    json_element['Value'] = [v for v in value]
+        if hasattr(json_element, 'Value'):
+            json_element['Value'] = jsonrep.convert_to_python_number(
+                json_element['Value'], self.VR
+            )
+        return json_element
+
     @property
     def value(self):
         """Return the element's `value`."""
@@ -378,7 +487,7 @@ class DataElement(object):
         elif self.VR == 'TM' and config.datetime_conversion:
             return pydicom.valuerep.TM(val)
         elif self.VR == "UI":
-            return UID(val)
+            return UID(val if val else '')
         elif not in_py2 and self.VR == "PN":
             return PersonName(val)
         # Later may need this for PersonName as for UI,
diff --git a/pydicom/dataset.py b/pydicom/dataset.py
index efc56d935..dd4415875 100644
--- a/pydicom/dataset.py
+++ b/pydicom/dataset.py
@@ -15,7 +15,6 @@ Dataset (dict subclass)
             contains its own DataElements, and so on in a recursive manner.
 """
 
-import base64
 import inspect  # for __dir__
 import io
 import json
@@ -27,7 +26,7 @@ from itertools import takewhile
 import pydicom  # for dcmwrite
 import pydicom.charset
 import pydicom.config
-from pydicom import compat, datadict
+from pydicom import compat, datadict, jsonrep
 from pydicom._version import __version_info__
 from pydicom.charset import default_encoding, convert_encodings
 from pydicom.config import logger
@@ -35,7 +34,6 @@ from pydicom.datadict import dictionary_VR
 from pydicom.datadict import (tag_for_keyword, keyword_for_tag,
                               repeater_has_keyword)
 from pydicom.dataelem import DataElement, DataElement_from_raw, RawDataElement
-from pydicom.multival import MultiValue
 from pydicom.pixel_data_handlers.util import (convert_color_space,
                                               reshape_pixel_array)
 from pydicom.tag import Tag, BaseTag, tag_in_exception
@@ -45,7 +43,6 @@ from pydicom.uid import (ExplicitVRLittleEndian, ImplicitVRLittleEndian,
 
 if compat.in_py2:
     from pkgutil import find_loader as have_package
-    from pydicom.valuerep import PersonNameUnicode
 else:
     from importlib.util import find_spec as have_package
 
@@ -343,13 +340,6 @@ class Dataset(dict):
     """
     indent_chars = "   "
 
-    _BINARY_VR_VALUES = ['OW', 'OB', 'OD', 'OF', 'OL', 'UN',
-                         'OB or OW', 'US or OW', 'US or SS or OW']
-    _VRs_TO_BE_FLOATS = ['DS', 'FL', 'FD', ]
-    _VRs_TO_BE_INTS = ['IS', 'SL', 'SS', 'UL', 'US', 'US or SS']
-
-    # Order of keys is significant!
-    _JSON_VALUE_KEYS = ('Value', 'BulkDataURI', 'InlineBinary', )
 
     # Python 2: Classes defining __eq__ should flag themselves as unhashable
     __hash__ = None
@@ -1400,7 +1390,7 @@ class Dataset(dict):
                                getattr(data_element, x))
                               for x in dir(data_element)
                               if not x.startswith("_")
-                              and x != "from_json"])
+                              and x not in ('from_json', 'to_json')])
             if data_element.VR == "SQ":
                 yield sequence_element_format % elem_dict
             else:
@@ -1776,43 +1766,11 @@ class Dataset(dict):
                     for dataset in sequence:
                         dataset.walk(callback)
 
-    @classmethod
-    def _convert_to_python_number(cls, value, vr):
-        """Makes sure that values are either ints or floats
-        based on their value representation.
-
-        Parameters
-        ----------
-        value: Union[Union[str, int, float], List[Union[str, int, float]]]
-            value of data element
-        vr: str
-            value representation of data element
-
-        Returns
-        -------
-        Union[Union[str, int, float], List[Union[str, int, float]]]
-
-        """
-        if value is None:
-            return None
-        number_type = None
-        if vr in cls._VRs_TO_BE_INTS:
-            number_type = int
-        if vr in cls._VRs_TO_BE_FLOATS:
-            number_type = float
-        if number_type is not None:
-            if isinstance(value, (list, tuple, )):
-                value = [number_type(e) for e in value]
-            else:
-                value = number_type(value)
-        return value
-
     @classmethod
     def from_json(cls, json_dataset, bulk_data_uri_handler=None,
                   encodings=None):
         """Loads DICOM Data Set in DICOM JSON format.
-        See:
-        http://dicom.nema.org/medical/dicom/current/output/chtml/part18/chapter_F.html
+        See PS 3.18, Annex F.
 
         Parameters
         ----------
@@ -1836,7 +1794,7 @@ class Dataset(dict):
         for tag, mapping in json_dataset.items():
             vr = mapping['vr']
             unique_value_keys = tuple(
-                set(mapping.keys()) & set(cls._JSON_VALUE_KEYS)
+                set(mapping.keys()) & set(jsonrep.JSON_VALUE_KEYS)
             )
             if len(unique_value_keys) == 0:
                 value_key = None
@@ -1850,119 +1808,18 @@ class Dataset(dict):
             dataset.add(data_element)
         return dataset
 
-    def _data_element_to_json(self, data_element,
-                              bulk_data_element_handler,
-                              bulk_data_threshold, dump_handler):
-        """Converts a DataElement to JSON representation.
-
-        Parameters
-        ----------
-        data_element: pydicom.dataelem.DataElement
-            data element
-        bulk_data_element_handler: Union[Callable, None]
-            callable that accepts a bulk data element and returns the
-            "BulkDataURI" for retrieving the value of the data element
-            via DICOMweb WADO-RS
-        bulk_data_threshold: int
-            size of base64 encoded data element above which a value will be
-            provided in form of a "BulkDataURI" rather than "InlineBinary"
-
-        Returns
-        -------
-        dict
-            mapping representing a JSON encoded data element
-
-        Raises
-        ------
-        TypeError
-            when size of encoded data element exceeds `bulk_data_threshold`
-            but `bulk_data_element_handler` is ``None`` and hence not callable
-
-        """
-        # TODO: Determine whether more VRs need to be converted to strings
-        _VRs_TO_QUOTE = ['AT', ]
-        json_element = {'vr': data_element.VR, }
-        if data_element.VR in Dataset._BINARY_VR_VALUES:
-            if data_element.value is not None:
-                binary_value = data_element.value
-                encoded_value = base64.b64encode(binary_value).decode('utf-8')
-                if len(encoded_value) > bulk_data_threshold:
-                    if bulk_data_element_handler is None:
-                        raise TypeError(
-                            'No bulk data element handler provided to generate '
-                            'URL for value of data element "{}".'.format(
-                                data_element.name
-                            )
-                        )
-                    json_element['BulkDataURI'] = bulk_data_element_handler(
-                        data_element
-                    )
-                else:
-                    logger.info(
-                        'encode bulk data element "{}" inline'.format(
-                            data_element.name
-                        )
-                    )
-                    json_element['InlineBinary'] = encoded_value
-        elif data_element.VR == 'SQ':
-            # recursive call to co-routine to format sequence contents
-            value = [
-                json.loads(e.to_json(
-                    bulk_data_element_handler=bulk_data_element_handler,
-                    bulk_data_threshold=bulk_data_threshold,
-                    dump_handler=dump_handler
-                ))
-                for e in data_element
-            ]
-            json_element['Value'] = value
-        elif data_element.VR == 'PN':
-            elem_value = data_element.value
-            if elem_value is not None:
-                if compat.in_py2:
-                    elem_value = PersonNameUnicode(elem_value, 'UTF8')
-                if len(elem_value.components) > 2:
-                    json_element['Value'] = [
-                        {'Phonetic': elem_value.components[2], },
-                    ]
-                elif len(elem_value.components) > 1:
-                    json_element['Value'] = [
-                        {'Ideographic': elem_value.components[1], },
-                    ]
-                else:
-                    json_element['Value'] = [
-                        {'Alphabetic': elem_value.components[0], },
-                    ]
-        else:
-            if data_element.value is not None:
-                is_multivalue = isinstance(data_element.value, MultiValue)
-                if data_element.VM > 1 or is_multivalue:
-                    value = data_element.value
-                else:
-                    value = [data_element.value]
-                # ensure it's a list and not another iterable
-                # (e.g. tuple), which would not be JSON serializable
-                if data_element.VR in _VRs_TO_QUOTE:
-                    json_element['Value'] = [str(v) for v in value]
-                else:
-                    json_element['Value'] = [v for v in value]
-        if hasattr(json_element, 'Value'):
-            json_element['Value'] = self._convert_to_python_number(
-                json_element['Value'], data_element.VR
-            )
-        return json_element
-
     def to_json(self, bulk_data_threshold=1, bulk_data_element_handler=None,
                 dump_handler=None):
         """Converts the data set into JSON representation based on the
-        DICOM JSON Model
-        http://dicom.nema.org/medical/dicom/current/output/chtml/part18/chapter_F.html.
+        DICOM JSON Model (see PS 3.18, Annex F).
 
         Parameters
         ----------
         bulk_data_threshold: int, optional
             threshold for the length of a base64-encoded binary data element
-            above which the element should be considered bulk data and the value
-            provided as a URI rather than included inline (default: ``1``)
+            above which the element should be considered bulk data and the
+            value provided as a URI rather than included inline
+            (default: ``1``)
         bulk_data_element_handler: Union[Callable, None], optional
             callable that accepts a bulk data element and returns a JSON
             representation of the data element (dictionary including the "vr"
@@ -1980,7 +1837,7 @@ class Dataset(dict):
         --------
         >>> def my_json_dumps(data):
         ...     return json.dumps(data, indent=4)
-        >>> dataset.to_json(dump_handler=my_json_dumps)
+        >>> Dataset.to_json(dump_handler=my_json_dumps)
 
         """
         if dump_handler is None:
@@ -1997,8 +1854,7 @@ class Dataset(dict):
                 )
                 continue
             data_element = self[key]
-            json_dataset[json_key] = self._data_element_to_json(
-                data_element,
+            json_dataset[json_key] = data_element.to_json(
                 bulk_data_element_handler=bulk_data_element_handler,
                 bulk_data_threshold=bulk_data_threshold,
                 dump_handler=dump_handler
diff --git a/pydicom/jsonrep.py b/pydicom/jsonrep.py
index 665d709c1..f6b12635e 100644
--- a/pydicom/jsonrep.py
+++ b/pydicom/jsonrep.py
@@ -2,11 +2,15 @@
 """Methods for converting Datasets and DataElements to/from json"""
 
 # Order of keys is significant!
-JSON_VALUE_KEYS = ('Value', 'BulkDataURI', 'InlineBinary', )
-VRs_TO_BE_FLOATS = ["DS", "FL", "FD", ]
-VRs_TO_BE_INTS = ["IS", "SL", "SS", "UL", "US", ]
+JSON_VALUE_KEYS = ('Value', 'BulkDataURI', 'InlineBinary',)
 
-def _convert_to_python_number(value, vr):
+BINARY_VR_VALUES = ['OW', 'OB', 'OD', 'OF', 'OL', 'UN',
+                    'OB or OW', 'US or OW', 'US or SS or OW']
+VRs_TO_BE_FLOATS = ['DS', 'FL', 'FD', ]
+VRs_TO_BE_INTS = ['IS', 'SL', 'SS', 'UL', 'US', 'US or SS']
+
+
+def convert_to_python_number(value, vr):
     """Makes sure that values are either ints or floats
     based on their value representation.
 
@@ -30,7 +34,7 @@ def _convert_to_python_number(value, vr):
     if vr in VRs_TO_BE_FLOATS:
         number_type = float
     if number_type is not None:
-        if isinstance(value, (list, tuple, )):
+        if isinstance(value, (list, tuple,)):
             value = [number_type(e) for e in value]
         else:
             value = number_type(value)
diff --git a/pydicom/multival.py b/pydicom/multival.py
index 178a1565b..e65ffffee 100644
--- a/pydicom/multival.py
+++ b/pydicom/multival.py
@@ -2,6 +2,7 @@
 """Code for multi-value data elements values,
 or any list of items that must all be the same type.
 """
+from pydicom import compat
 
 try:
     from collections.abc import MutableSequence
@@ -30,7 +31,7 @@ class MultiValue(MutableSequence):
         :param type_constructor: a constructor for the required
                            type for all list items. Could be the
                            class, or a factory function. For DICOM
-                           mult-value data elements, this will be the
+                           multi-value data elements, this will be the
                            class or type corresponding to the VR.
         :param iterable: an iterable (e.g. list, tuple) of items
                         to initialize the MultiValue list
@@ -59,8 +60,11 @@ class MultiValue(MutableSequence):
             self._list.__setitem__(i, self.type_constructor(val))
 
     def __str__(self):
-        lines = [str(x) for x in self]
-        return "['" + "', '".join(lines) + "']"
+        if not self:
+            return ''
+        lines = ["'{}'".format(x) if isinstance(x, compat.char_types)
+                 else str(x) for x in self]
+        return "[" + ", ".join(lines) + "]"
 
     __repr__ = __str__
 
diff --git a/pydicom/valuerep.py b/pydicom/valuerep.py
index 49e857802..14ef2950e 100644
--- a/pydicom/valuerep.py
+++ b/pydicom/valuerep.py
@@ -603,8 +603,6 @@ def _encode_personname(components, encodings):
 
 class PersonName3(object):
     def __init__(self, val, encodings=None, original_string=None):
-        # handle None `val` as empty string
-        val = val or ''
         if isinstance(val, PersonName3):
             encodings = val.encodings
             self.original_string = val.original_string
@@ -614,6 +612,9 @@ class PersonName3(object):
             self.original_string = val
             self._components = None
         else:
+            # handle None `val` as empty string
+            val = val or ''
+
             # this is the decoded string - save the original string if
             # available for easier writing back
             self.original_string = original_string
@@ -774,6 +775,12 @@ class PersonName3(object):
         self._create_dict()
         return format_str % self._dict
 
+    def __bool__(self):
+        if self.original_string is None:
+            return (self._components is not None and
+                    (len(self._components) > 1 or bool(self._components[0])))
+        return bool(self.original_string)
+
 
 class PersonNameBase(object):
     """Base class for Person Name classes"""
diff --git a/setup.py b/setup.py
index c6f151ff7..6955f9ac6 100755
--- a/setup.py
+++ b/setup.py
@@ -40,6 +40,7 @@ CLASSIFIERS = [
     "Programming Language :: Python :: 3.4",
     "Programming Language :: Python :: 3.5",
     "Programming Language :: Python :: 3.6",
+    "Programming Language :: Python :: 3.7",
     "Operating System :: OS Independent",
     "Topic :: Scientific/Engineering :: Medical Science Apps.",
     "Topic :: Scientific/Engineering :: Physics",


Test patch:
diff --git a/pydicom/tests/test_charset.py b/pydicom/tests/test_charset.py
index 007ab8e53..59620556e 100644
--- a/pydicom/tests/test_charset.py
+++ b/pydicom/tests/test_charset.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""unittest cases for pydicom.charset module"""
+"""Unit tests for the pydicom.charset module."""
 
 import pytest
 
diff --git a/pydicom/tests/test_config.py b/pydicom/tests/test_config.py
new file mode 100644
index 000000000..66824c709
--- /dev/null
+++ b/pydicom/tests/test_config.py
@@ -0,0 +1,107 @@
+# Copyright 2008-2019 pydicom authors. See LICENSE file for details.
+"""Unit tests for the pydicom.config module."""
+
+import logging
+import sys
+
+import pytest
+
+from pydicom import dcmread
+from pydicom.config import debug
+from pydicom.data import get_testdata_files
+
+
+DS_PATH = get_testdata_files("CT_small.dcm")[0]
+PYTEST = [int(x) for x in pytest.__version__.split('.')]
+
+
+@pytest.mark.skipif(PYTEST[:2] < [3, 4], reason='no caplog')
+class TestDebug(object):
+    """Tests for config.debug()."""
+    def setup(self):
+        self.logger = logging.getLogger('pydicom')
+
+    def teardown(self):
+        # Reset to just NullHandler
+        self.logger.handlers = [self.logger.handlers[0]]
+
+    def test_default(self, caplog):
+        """Test that the default logging handler is a NullHandler."""
+        assert 1 == len(self.logger.handlers)
+        assert isinstance(self.logger.handlers[0], logging.NullHandler)
+
+        with caplog.at_level(logging.DEBUG, logger='pydicom'):
+            ds = dcmread(DS_PATH)
+
+            assert "Call to dcmread()" not in caplog.text
+            assert "Reading File Meta Information preamble..." in caplog.text
+            assert "Reading File Meta Information prefix..." in caplog.text
+            assert "00000080: 'DICM' prefix found" in caplog.text
+
+    def test_debug_on_handler_null(self, caplog):
+        """Test debug(True, False)."""
+        debug(True, False)
+        assert 1 == len(self.logger.handlers)
+        assert isinstance(self.logger.handlers[0], logging.NullHandler)
+
+        with caplog.at_level(logging.DEBUG, logger='pydicom'):
+            ds = dcmread(DS_PATH)
+
+            assert "Call to dcmread()" in caplog.text
+            assert "Reading File Meta Information preamble..." in caplog.text
+            assert "Reading File Meta Information prefix..." in caplog.text
+            assert "00000080: 'DICM' prefix found" in caplog.text
+            msg = (
+                "00009848: fc ff fc ff 4f 42 00 00 7e 00 00 00    "
+                "(fffc, fffc) OB Length: 126"
+            )
+            assert msg in caplog.text
+
+    def test_debug_off_handler_null(self, caplog):
+        """Test debug(False, False)."""
+        debug(False, False)
+        assert 1 == len(self.logger.handlers)
+        assert isinstance(self.logger.handlers[0], logging.NullHandler)
+
+        with caplog.at_level(logging.DEBUG, logger='pydicom'):
+            ds = dcmread(DS_PATH)
+
+            assert "Call to dcmread()" not in caplog.text
+            assert "Reading File Meta Information preamble..." in caplog.text
+            assert "Reading File Meta Information prefix..." in caplog.text
+            assert "00000080: 'DICM' prefix found" in caplog.text
+
+    def test_debug_on_handler_stream(self, caplog):
+        """Test debug(True, True)."""
+        debug(True, True)
+        assert 2 == len(self.logger.handlers)
+        assert isinstance(self.logger.handlers[0], logging.NullHandler)
+        assert isinstance(self.logger.handlers[1], logging.StreamHandler)
+
+        with caplog.at_level(logging.DEBUG, logger='pydicom'):
+            ds = dcmread(DS_PATH)
+
+            assert "Call to dcmread()" in caplog.text
+            assert "Reading File Meta Information preamble..." in caplog.text
+            assert "Reading File Meta Information prefix..." in caplog.text
+            assert "00000080: 'DICM' prefix found" in caplog.text
+            msg = (
+                "00009848: fc ff fc ff 4f 42 00 00 7e 00 00 00    "
+                "(fffc, fffc) OB Length: 126"
+            )
+            assert msg in caplog.text
+
+    def test_debug_off_handler_stream(self, caplog):
+        """Test debug(False, True)."""
+        debug(False, True)
+        assert 2 == len(self.logger.handlers)
+        assert isinstance(self.logger.handlers[0], logging.NullHandler)
+        assert isinstance(self.logger.handlers[1], logging.StreamHandler)
+
+        with caplog.at_level(logging.DEBUG, logger='pydicom'):
+            ds = dcmread(DS_PATH)
+
+            assert "Call to dcmread()" not in caplog.text
+            assert "Reading File Meta Information preamble..." in caplog.text
+            assert "Reading File Meta Information prefix..." in caplog.text
+            assert "00000080: 'DICM' prefix found" in caplog.text
diff --git a/pydicom/tests/test_dataelem.py b/pydicom/tests/test_dataelem.py
index a5011c867..8bd68fe11 100644
--- a/pydicom/tests/test_dataelem.py
+++ b/pydicom/tests/test_dataelem.py
@@ -1,10 +1,10 @@
+# -*- coding: utf-8 -*-
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""unittest cases for pydicom.dataelem module"""
+"""Unit tests for the pydicom.dataelem module."""
 
 # Many tests of DataElement class are implied in test_dataset also
 
 import sys
-import unittest
 
 import pytest
 
@@ -15,13 +15,15 @@ from pydicom.dataelem import (
     DataElement_from_raw,
 )
 from pydicom.dataset import Dataset
+from pydicom.multival import MultiValue
 from pydicom.tag import Tag
 from pydicom.uid import UID
 from pydicom.valuerep import DSfloat
 
 
-class DataElementTests(unittest.TestCase):
-    def setUp(self):
+class TestDataElement(object):
+    """Tests for dataelem.DataElement."""
+    def setup(self):
         self.data_elementSH = DataElement((1, 2), "SH", "hello")
         self.data_elementIS = DataElement((1, 2), "IS", "42")
         self.data_elementDS = DataElement((1, 2), "DS", "42.00001")
@@ -31,179 +33,170 @@ class DataElementTests(unittest.TestCase):
         self.data_elementPrivate = DataElement(0x00090000, 'UL', 101)
         self.data_elementRetired = DataElement(0x00080010, 'SH', 102)
 
-    def testVM1(self):
-        """DataElement: return correct value multiplicity for VM > 1........"""
-        VM = self.data_elementMulti.VM
-        self.assertEqual(VM, 3,
-                         "Wrong Value Multiplicity, expected 3, got %i" % VM)
+    def test_VM_1(self):
+        """DataElement: return correct value multiplicity for VM > 1"""
+        assert 3 == self.data_elementMulti.VM
 
-    def testVM2(self):
-        """DataElement: return correct value multiplicity for VM = 1........"""
-        VM = self.data_elementIS.VM
-        self.assertEqual(VM, 1,
-                         "Wrong Value Multiplicity, expected 1, got %i" % VM)
+    def test_VM_2(self):
+        """DataElement: return correct value multiplicity for VM = 1"""
+        assert 1 == self.data_elementIS.VM
 
-    def testDSFloatConversion(self):
+    def test_DSFloat_conversion(self):
         """Test that strings are correctly converted if changing the value."""
-        self.assertTrue(isinstance(self.data_elementDS.value, DSfloat))
-        self.assertTrue(isinstance(self.data_elementMulti.value[0], DSfloat))
-        self.assertEqual(DSfloat('42.1'), self.data_elementMulti.value[0])
+        assert isinstance(self.data_elementDS.value, DSfloat)
+        assert isinstance(self.data_elementMulti.value[0], DSfloat)
+        assert DSfloat('42.1') == self.data_elementMulti.value[0]
 
         # multi-value append/insert
         self.data_elementMulti.value.append('42.4')
-        self.assertTrue(isinstance(self.data_elementMulti.value[3], DSfloat))
-        self.assertEqual(DSfloat('42.4'), self.data_elementMulti.value[3])
+        assert isinstance(self.data_elementMulti.value[3], DSfloat)
+        assert DSfloat('42.4') == self.data_elementMulti.value[3]
 
         self.data_elementMulti.value.insert(0, '42.0')
-        self.assertTrue(isinstance(self.data_elementMulti.value[0], DSfloat))
-        self.assertEqual(DSfloat('42.0'), self.data_elementMulti.value[0])
+        assert isinstance(self.data_elementMulti.value[0], DSfloat)
+        assert DSfloat('42.0') == self.data_elementMulti.value[0]
 
         # change single value of multi-value
         self.data_elementMulti.value[3] = '123.4'
-        self.assertTrue(isinstance(self.data_elementMulti.value[3], DSfloat))
-        self.assertEqual(DSfloat('123.4'), self.data_elementMulti.value[3])
+        assert isinstance(self.data_elementMulti.value[3], DSfloat)
+        assert DSfloat('123.4') == self.data_elementMulti.value[3]
 
-    def testBackslash(self):
+    def test_backslash(self):
         """DataElement: String with '\\' sets multi-valued data_element."""
         data_element = DataElement((1, 2), "DS", r"42.1\42.2\42.3")
-        self.assertEqual(data_element.VM, 3, "Did not get a mult-valued value")
+        assert 3 == data_element.VM
 
-    def testUID(self):
-        """DataElement: setting or changing UID results in UID type........."""
+    def test_UID(self):
+        """DataElement: setting or changing UID results in UID type."""
         ds = Dataset()
         ds.TransferSyntaxUID = "1.2.3"
-        self.assertTrue(isinstance(ds.TransferSyntaxUID, UID),
-                        "Assignment to UID did not create UID class")
+        assert isinstance(ds.TransferSyntaxUID, UID)
         ds.TransferSyntaxUID += ".4.5.6"
-        self.assertTrue(isinstance(ds.TransferSyntaxUID, UID),
-                        "+= to UID did not keep as UID class")
+        assert isinstance(ds.TransferSyntaxUID, UID)
 
-    def testKeyword(self):
+    def test_keyword(self):
         """DataElement: return correct keyword"""
-        self.assertEqual(self.data_elementCommand.keyword,
-                         'CommandGroupLength')
+        assert 'CommandGroupLength' == self.data_elementCommand.keyword
+        assert '' == self.data_elementPrivate.keyword
 
-        self.assertEqual(self.data_elementPrivate.keyword,
-                         '')
-
-    def testRetired(self):
+    def test_retired(self):
         """DataElement: return correct is_retired"""
-        self.assertEqual(self.data_elementCommand.is_retired, False)
-        self.assertEqual(self.data_elementRetired.is_retired, True)
-        self.assertEqual(self.data_elementPrivate.is_retired, False)
+        assert self.data_elementCommand.is_retired is False
+        assert self.data_elementRetired.is_retired is True
+        assert self.data_elementPrivate.is_retired is False
 
     def test_description_group_length(self):
         """Test DataElement.description for Group Length element"""
         elem = DataElement(0x00100000, 'LO', 12345)
-        assert elem.description() == 'Group Length'
+        assert 'Group Length' == elem.description()
 
     def test_description_unknown_private(self):
         """Test DataElement.description with an unknown private element"""
         elem = DataElement(0x00110010, 'LO', 12345)
         elem.private_creator = 'TEST'
-        assert elem.description() == 'Private tag data'
+        assert 'Private tag data' == elem.description()
         elem = DataElement(0x00110F00, 'LO', 12345)
         assert elem.tag.is_private
         assert not hasattr(elem, 'private_creator')
-        assert elem.description() == 'Private tag data'
+        assert 'Private tag data' == elem.description()
 
     def test_description_unknown(self):
         """Test DataElement.description with an unknown element"""
         elem = DataElement(0x00000004, 'LO', 12345)
-        assert elem.description() == ''
+        assert '' == elem.description()
 
-    def testEqualityStandardElement(self):
+    def test_equality_standard_element(self):
         """DataElement: equality returns correct value for simple elements"""
         dd = DataElement(0x00100010, 'PN', 'ANON')
-        self.assertTrue(dd == dd)
+        assert dd == dd
         ee = DataElement(0x00100010, 'PN', 'ANON')
-        self.assertTrue(dd == ee)
+        assert dd == ee
 
         # Check value
         ee.value = 'ANAN'
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check tag
         ee = DataElement(0x00100011, 'PN', 'ANON')
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check VR
         ee = DataElement(0x00100010, 'SH', 'ANON')
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         dd = DataElement(0x00080018, 'UI', '1.2.3.4')
         ee = DataElement(0x00080018, 'UI', '1.2.3.4')
-        self.assertTrue(dd == ee)
+        assert dd == ee
 
         ee = DataElement(0x00080018, 'PN', '1.2.3.4')
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
-    def testEqualityPrivateElement(self):
+    def test_equality_private_element(self):
         """DataElement: equality returns correct value for private elements"""
         dd = DataElement(0x01110001, 'PN', 'ANON')
-        self.assertTrue(dd == dd)
+        assert dd == dd
         ee = DataElement(0x01110001, 'PN', 'ANON')
-        self.assertTrue(dd == ee)
+        assert dd == ee
 
         # Check value
         ee.value = 'ANAN'
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check tag
         ee = DataElement(0x01110002, 'PN', 'ANON')
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check VR
         ee = DataElement(0x01110001, 'SH', 'ANON')
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
-    def testEqualitySequenceElement(self):
+    def test_equality_sequence_element(self):
         """DataElement: equality returns correct value for sequence elements"""
         dd = DataElement(0x300A00B0, 'SQ', [])
-        self.assertTrue(dd == dd)
+        assert dd == dd
         ee = DataElement(0x300A00B0, 'SQ', [])
-        self.assertTrue(dd == ee)
+        assert dd == ee
 
         # Check value
         e = Dataset()
         e.PatientName = 'ANON'
         ee.value = [e]
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check tag
         ee = DataElement(0x01110002, 'SQ', [])
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check VR
         ee = DataElement(0x300A00B0, 'SH', [])
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         # Check with dataset
         dd = DataElement(0x300A00B0, 'SQ', [Dataset()])
         dd.value[0].PatientName = 'ANON'
         ee = DataElement(0x300A00B0, 'SQ', [Dataset()])
         ee.value[0].PatientName = 'ANON'
-        self.assertTrue(dd == ee)
+        assert dd == ee
 
         # Check uneven sequences
         dd.value.append(Dataset())
         dd.value[1].PatientName = 'ANON'
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
         ee.value.append(Dataset())
         ee.value[1].PatientName = 'ANON'
-        self.assertTrue(dd == ee)
+        assert dd == ee
         ee.value.append(Dataset())
         ee.value[2].PatientName = 'ANON'
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
-    def testEqualityNotElement(self):
+    def test_equality_not_rlement(self):
         """DataElement: equality returns correct value when not same class"""
         dd = DataElement(0x00100010, 'PN', 'ANON')
         ee = {'0x00100010': 'ANON'}
-        self.assertFalse(dd == ee)
+        assert not dd == ee
 
-    def testEqualityInheritance(self):
+    def test_equality_inheritance(self):
         """DataElement: equality returns correct value for subclasses"""
 
         class DataElementPlus(DataElement):
@@ -211,13 +204,13 @@ class DataElementTests(unittest.TestCase):
 
         dd = DataElement(0x00100010, 'PN', 'ANON')
         ee = DataElementPlus(0x00100010, 'PN', 'ANON')
-        self.assertTrue(ee == ee)
-        self.assertTrue(dd == ee)
-        self.assertTrue(ee == dd)
+        assert ee == ee
+        assert dd == ee
+        assert ee == dd
 
         ee = DataElementPlus(0x00100010, 'PN', 'ANONY')
-        self.assertFalse(dd == ee)
-        self.assertFalse(ee == dd)
+        assert not dd == ee
+        assert not ee == dd
 
     def test_equality_class_members(self):
         """Test equality is correct when ignored class members differ."""
@@ -226,54 +219,45 @@ class DataElementTests(unittest.TestCase):
         dd.file_tell = 10
         dd.maxBytesToDisplay = 0
         dd.descripWidth = 0
-        ee = DataElement(0x00100010, 'PN', 'ANON')
-        self.assertTrue(dd == ee)
+        assert DataElement(0x00100010, 'PN', 'ANON') == dd
 
     def test_inequality_standard(self):
         """Test DataElement.__ne__ for standard element"""
         dd = DataElement(0x00100010, 'PN', 'ANON')
         assert not dd != dd
-        ee = DataElement(0x00100010, 'PN', 'ANONA')
-        assert dd != ee
+        assert DataElement(0x00100010, 'PN', 'ANONA') != dd
 
         # Check tag
-        ee = DataElement(0x00100011, 'PN', 'ANON')
-        assert dd != ee
+        assert DataElement(0x00100011, 'PN', 'ANON') != dd
 
         # Check VR
-        ee = DataElement(0x00100010, 'SH', 'ANON')
-        assert dd != ee
+        assert DataElement(0x00100010, 'SH', 'ANON') != dd
 
     def test_inequality_sequence(self):
         """Test DataElement.__ne__ for sequence element"""
         dd = DataElement(0x300A00B0, 'SQ', [])
         assert not dd != dd
-        ee = DataElement(0x300A00B0, 'SQ', [])
-        assert not dd != ee
+        assert not DataElement(0x300A00B0, 'SQ', []) != dd
         ee = DataElement(0x300A00B0, 'SQ', [Dataset()])
-        assert dd != ee
+        assert ee != dd
 
         # Check value
         dd.value = [Dataset()]
         dd[0].PatientName = 'ANON'
         ee[0].PatientName = 'ANON'
-        assert not dd != ee
+        assert not ee != dd
         ee[0].PatientName = 'ANONA'
-        assert dd != ee
-
-    def testHash(self):
-        """DataElement: hash returns TypeErrpr"""
-        dd = DataElement(0x00100010, 'PN', 'ANON')
-
-        def test_hash():
-            hash(dd)
+        assert ee != dd
 
-        self.assertRaises(TypeError, test_hash)
+    def test_hash(self):
+        """Test hash(DataElement) raises TypeError"""
+        with pytest.raises(TypeError, match=r"unhashable"):
+            hash(DataElement(0x00100010, 'PN', 'ANON'))
 
     def test_repeater_str(self):
         """Test a repeater group element displays the element name."""
         elem = DataElement(0x60023000, 'OB', b'\x00')
-        self.assertTrue('Overlay Data' in elem.__str__())
+        assert 'Overlay Data' in elem.__str__()
 
     def test_str_no_vr(self):
         """Test DataElement.__str__ output with no VR"""
@@ -290,15 +274,15 @@ class DataElementTests(unittest.TestCase):
         elem[0].PatientID = '1234'
         assert repr(elem) == repr(elem.value)
 
-    @unittest.skipIf(sys.version_info >= (3, ), 'Testing Python 2 behavior')
+    @pytest.mark.skipif(sys.version_info >= (3, ), reason='Python 2 behavior')
     def test_unicode(self):
         """Test unicode representation of the DataElement"""
         elem = DataElement(0x00100010, 'PN', u'ANON')
         # Make sure elem.value is actually unicode
         assert isinstance(elem.value, unicode)
-        assert unicode(elem) == (
+        assert (
             u"(0010, 0010) Patient's Name                      PN: ANON"
-        )
+        ) == unicode(elem)
         assert isinstance(unicode(elem), unicode)
         assert not isinstance(unicode(elem), str)
         # Make sure elem.value is still unicode
@@ -307,9 +291,9 @@ class DataElementTests(unittest.TestCase):
         # When value is not in compat.text_type
         elem = DataElement(0x00100010, 'LO', 12345)
         assert isinstance(unicode(elem), unicode)
-        assert unicode(elem) == (
+        assert (
             u"(0010, 0010) Patient's Name                      LO: 12345"
-        )
+        ) == unicode(elem)
 
     def test_getitem_raises(self):
         """Test DataElement.__getitem__ raise if value not indexable"""
@@ -368,46 +352,172 @@ class DataElementTests(unittest.TestCase):
         assert '[Overlay ID]' == private_data_elem.name
         assert 'UN' == private_data_elem.VR
 
+    def test_known_tags_with_UN_VR(self):
+        """Known tags with VR UN are correctly decoded."""
+        ds = Dataset()
+        ds[0x00080005] = DataElement(0x00080005, 'UN', b'ISO_IR 126')
+        ds[0x00100010] = DataElement(0x00100010, 'UN',
+                                     u'Διονυσιος'.encode('iso_ir_126'))
+        ds.decode()
+        assert 'CS' == ds[0x00080005].VR
+        assert 'PN' == ds[0x00100010].VR
+        assert u'Διονυσιος' == ds[0x00100010].value
 
-class RawDataElementTests(unittest.TestCase):
-    def testKeyError(self):
+        ds = Dataset()
+        ds[0x00080005] = DataElement(0x00080005, 'UN',
+                                     b'ISO 2022 IR 100\\ISO 2022 IR 126')
+        ds[0x00100010] = DataElement(0x00100010, 'UN',
+                                     b'Dionysios=\x1b\x2d\x46'
+                                     + u'Διονυσιος'.encode('iso_ir_126'))
+        ds.decode()
+        assert 'CS' == ds[0x00080005].VR
+        assert 'PN' == ds[0x00100010].VR
+        assert u'Dionysios=Διονυσιος' == ds[0x00100010].value
+
+    def test_unknown_tags_with_UN_VR(self):
+        """Unknown tags with VR UN are not decoded."""
+        ds = Dataset()
+        ds[0x00080005] = DataElement(0x00080005, 'CS', b'ISO_IR 126')
+        ds[0x00111010] = DataElement(0x00111010, 'UN',
+                                     u'Διονυσιος'.encode('iso_ir_126'))
+        ds.decode()
+        assert 'UN' == ds[0x00111010].VR
+        assert u'Διονυσιος'.encode('iso_ir_126') == ds[0x00111010].value
+
+    def test_tag_with_long_value_UN_VR(self):
+        """Tag with length > 64kb with VR UN is not changed."""
+        ds = Dataset()
+        ds[0x00080005] = DataElement(0x00080005, 'CS', b'ISO_IR 126')
+
+        single_value = b'123456.789012345'
+        large_value = b'\\'.join([single_value] * 4500)
+        ds[0x30040058] = DataElement(0x30040058, 'UN',
+                                     large_value,
+                                     is_undefined_length=False)
+        ds.decode()
+        assert 'UN' == ds[0x30040058].VR
+
+    def test_empty_text_values(self):
+        """Test that assigning an empty value behaves as expected."""
+        def check_empty_text_element(value):
+            setattr(ds, tag_name, value)
+            elem = ds[tag_name]
+            assert bool(elem.value) is False
+
+        text_vrs = {
+            'AE': 'Receiver',
+            'AS': 'PatientAge',
+            'AT': 'OffendingElement',
+            'CS': 'QualityControlSubject',
+            'DA': 'PatientBirthDate',
+            'DS': 'PatientWeight',
+            'DT': 'AcquisitionDateTime',
+            'IS': 'BeamNumber',
+            'LO': 'DataSetSubtype',
+            'LT': 'ExtendedCodeMeaning',
+            'PN': 'PatientName',
+            'SH': 'CodeValue',
+            'ST': 'InstitutionAddress',
+            'TM': 'StudyTime',
+            'UC': 'LongCodeValue',
+            'UI': 'SOPClassUID',
+            'UR': 'CodingSchemeURL',
+            'UT': 'StrainAdditionalInformation',
+        }
+        ds = Dataset()
+        # set value to new element
+        for tag_name in text_vrs.values():
+            check_empty_text_element(None)
+            del ds[tag_name]
+            check_empty_text_element(b'')
+            del ds[tag_name]
+            check_empty_text_element(u'')
+            del ds[tag_name]
+            check_empty_text_element([])
+            del ds[tag_name]
+
+        # set value to existing element
+        for tag_name in text_vrs.values():
+            check_empty_text_element(None)
+            check_empty_text_element(b'')
+            check_empty_text_element(u'')
+            check_empty_text_element([])
+            check_empty_text_element(None)
+
+    def test_empty_binary_values(self):
+        """Test that assigning an empty value behaves as expected for
+        non-text VRs."""
+        def check_empty_binary_element(value):
+            setattr(ds, tag_name, value)
+            elem = ds[tag_name]
+            assert bool(elem.value) is False
+
+        non_text_vrs = {
+            'SL': 'RationalNumeratorValue',
+            'SS': 'SelectorSSValue',
+            'UL': 'SimpleFrameList',
+            'US': 'SourceAcquisitionBeamNumber',
+            'FD': 'RealWorldValueLUTData',
+            'FL': 'VectorAccuracy',
+            'OB': 'FillPattern',
+            'OD': 'DoubleFloatPixelData',
+            'OF': 'UValueData',
+            'OL': 'TrackPointIndexList',
+            'OW': 'TrianglePointIndexList',
+            'UN': 'SelectorUNValue',
+        }
+        ds = Dataset()
+        # set value to new element
+        for tag_name in non_text_vrs.values():
+            check_empty_binary_element(None)
+            del ds[tag_name]
+            check_empty_binary_element([])
+            del ds[tag_name]
+            check_empty_binary_element(MultiValue(int, []))
+            del ds[tag_name]
+
+        # set value to existing element
+        for tag_name in non_text_vrs.values():
+            check_empty_binary_element(None)
+            check_empty_binary_element([])
+            check_empty_binary_element(MultiValue(int, []))
+            check_empty_binary_element(None)
+
+
+class TestRawDataElement(object):
+    """Tests for dataelem.RawDataElement."""
+    def test_key_error(self):
         """RawDataElement: conversion of unknown tag throws KeyError..."""
         # raw data element -> tag VR length value
         #                       value_tell is_implicit_VR is_little_endian'
         # Unknown (not in DICOM dict), non-private, non-group 0 for this test
         raw = RawDataElement(Tag(0x88880002), None, 4, 0x1111,
                              0, True, True)
-        self.assertRaises(KeyError, DataElement_from_raw, raw)
 
-    def testValidTag(self):
+        with pytest.raises(KeyError, match=r"\(8888, 0002\)"):
+            DataElement_from_raw(raw)
+
+    def test_valid_tag(self):
         """RawDataElement: conversion of known tag succeeds..."""
         raw = RawDataElement(Tag(0x00080020), 'DA', 8, b'20170101',
                              0, False, True)
         element = DataElement_from_raw(raw, default_encoding)
-        self.assertEqual(element.name, 'Study Date')
-        self.assertEqual(element.VR, 'DA')
-        self.assertEqual(element.value, '20170101')
+        assert 'Study Date' == element.name
+        assert 'DA' == element.VR
+        assert '20170101' == element.value
 
         raw = RawDataElement(Tag(0x00080000), None, 4, b'\x02\x00\x00\x00',
                              0, True, True)
         elem = DataElement_from_raw(raw, default_encoding)
-        assert elem.VR == 'UL'
+        assert 'UL' == elem.VR
 
-    @unittest.skipIf(sys.version_info >= (3, ), 'Testing Python 2 behavior')
-    def testTagWithoutEncodingPython2(self):
-        """RawDataElement: no encoding needed in Python 2."""
+    def test_data_element_without_encoding(self):
+        """RawDataElement: no encoding needed."""
         raw = RawDataElement(Tag(0x00104000), 'LT', 23,
                              b'comment\\comment2\\comment3',
                              0, False, True)
         element = DataElement_from_raw(raw)
-        self.assertEqual(element.name, 'Patient Comments')
-
-    @unittest.skipIf(sys.version_info < (3, ), 'Testing Python 3 behavior')
-    def testTagWithoutEncodingPython3(self):
-        """RawDataElement: raises if no encoding given in Python 3."""
-        self.assertRaises(TypeError, RawDataElement(Tag(0x00104000), 'LT', 14,
-                                                    b'comment1\\comment2',
-                                                    0, False, True))
+        assert 'Patient Comments' == element.name
 
     def test_unknown_vr(self):
         """Test converting a raw element with unknown VR"""
diff --git a/pydicom/tests/test_dataset.py b/pydicom/tests/test_dataset.py
index 7fd3d09c4..d01596639 100644
--- a/pydicom/tests/test_dataset.py
+++ b/pydicom/tests/test_dataset.py
@@ -1,7 +1,5 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""Tests for dataset.py"""
-
-import unittest
+"""Unit tests for the pydicom.dataset module."""
 
 import pytest
 
@@ -21,38 +19,19 @@ from pydicom.uid import (
 )
 
 
-class DatasetTests(unittest.TestCase):
-    def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
-        """Redefine unittest Exception test to return the exception object"""
-        try:
-            callableObj(*args, **kwargs)
-        except excClass as e:
-            return e
-        else:
-            if hasattr(excClass, '__name__'):
-                excName = excClass.__name__
-            else:
-                excName = str(excClass)
-            raise self.failureException("{0:s} not raised".format(excName))
-
-    def failUnlessExceptionArgs(self, start_args, excClass, callableObj):
-        """Check the expected args were returned from an exception
-        start_args -- a string with the start of the expected message
-        """
-        if not compat.in_py2:
-            with self.assertRaises(excClass) as cm:
-                callableObj()
-
-            excObj = cm.exception
-        else:
-            excObj = self.failUnlessRaises(excClass, callableObj)
-
-        msg = "\nExpected Exception message:\n" + start_args
-        msg += "\nGot:\n" + excObj.args[0]
-        self.assertTrue(excObj.args[0].startswith(start_args), msg)
-
-    def testAttributeErrorInProperty(self):
-        """Dataset: AttributeError in property raises actual error message.."""
+class BadRepr(object):
+    def __repr__(self):
+        raise ValueError("bad repr")
+
+
+class TestDataset(object):
+    """Tests for dataset.Dataset."""
+    def setup(self):
+        self.ds = Dataset()
+        self.ds.TreatmentMachineName = "unit001"
+
+    def test_attribute_error_in_property(self):
+        """Dataset: AttributeError in property raises actual error message."""
         # This comes from bug fix for issue 42
         # First, fake enough to try the pixel_array property
         ds = Dataset()
@@ -129,247 +108,183 @@ class DatasetTests(unittest.TestCase):
             ds = Foo()
             ds.bar
 
-        self.assertRaises(AttributeError, test)
-        msg = "'Foo' object has no attribute '_barr'"
-        self.failUnlessExceptionArgs(msg, AttributeError, test)
+        msg = r"'Foo' object has no attribute '_barr'"
+        with pytest.raises(AttributeError, match=msg):
+            test()
 
-    def testTagExceptionPrint(self):
-        # When printing datasets, a tag number should appear in error
-        # messages
+    def test_tag_exception_print(self):
+        """Test that tag appears in exception messages."""
         ds = Dataset()
         ds.PatientID = "123456"  # Valid value
         ds.SmallestImagePixelValue = BadRepr()  # Invalid value
 
-        expected_msg = ("With tag (0028, 0106) got exception: "
-                        "bad repr")
-
-        self.failUnlessExceptionArgs(expected_msg, ValueError, lambda: str(ds))
+        msg = r"With tag \(0028, 0106\) got exception: bad repr"
+        with pytest.raises(ValueError, match=msg):
+            str(ds)
 
-    def testTagExceptionWalk(self):
-        # When recursing through dataset, a tag number should appear in
-        # error messages
+    def test_tag_exception_walk(self):
+        """Test that tag appears in exceptions raised during recursion."""
         ds = Dataset()
         ds.PatientID = "123456"  # Valid value
         ds.SmallestImagePixelValue = BadRepr()  # Invalid value
 
-        expected_msg = ("With tag (0028, 0106) got exception: "
-                        "bad repr")
-
         def callback(dataset, data_element):
             return str(data_element)
 
         def func(dataset=ds):
             return dataset.walk(callback)
 
-        self.failUnlessExceptionArgs(expected_msg, ValueError, func)
-
-    def dummy_dataset(self):
-        # This dataset is used by many of the tests
-        ds = Dataset()
-        ds.add_new((0x300a, 0x00b2), "SH", "unit001")  # TreatmentMachineName
-        return ds
+        msg = r"With tag \(0028, 0106\) got exception: bad repr"
+        with pytest.raises(ValueError, match=msg):
+            func()
 
-    def testSetNewDataElementByName(self):
-        """Dataset: set new data_element by name............................"""
+    def test_set_new_data_element_by_name(self):
+        """Dataset: set new data_element by name."""
         ds = Dataset()
         ds.TreatmentMachineName = "unit #1"
         data_element = ds[0x300a, 0x00b2]
-        self.assertEqual(data_element.value, "unit #1",
-                         "Unable to set data_element by name")
-        self.assertEqual(data_element.VR, "SH",
-                         "data_element not the expected VR")
-
-    def testSetExistingDataElementByName(self):
-        """Dataset: set existing data_element by name......................."""
-        ds = self.dummy_dataset()
-        ds.TreatmentMachineName = "unit999"  # change existing value
-        self.assertEqual(ds[0x300a, 0x00b2].value, "unit999")
-
-    def testSetNonDicom(self):
-        """Dataset: can set class instance property (non-dicom)............."""
+        assert "unit #1" == data_element.value
+        assert "SH" == data_element.VR
+
+    def test_set_existing_data_element_by_name(self):
+        """Dataset: set existing data_element by name."""
+        self.ds.TreatmentMachineName = "unit999"  # change existing value
+        assert "unit999" == self.ds[0x300a, 0x00b2].value
+
+    def test_set_non_dicom(self):
+        """Dataset: can set class instance property (non-dicom)."""
         ds = Dataset()
         ds.SomeVariableName = 42
-        has_it = hasattr(ds, 'SomeVariableName')
-        self.assertTrue(has_it, "Variable did not get created")
-        if has_it:
-            self.assertEqual(
-                ds.SomeVariableName,
-                42,
-                "There, but wrong value")
-
-    def testMembership(self):
-        """Dataset: can test if item present by 'if <name> in dataset'......"""
-        ds = self.dummy_dataset()
-        self.assertTrue(
-            'TreatmentMachineName' in ds, "membership test failed")
-        self.assertTrue(
-            'Dummyname' not in ds, "non-member tested as member")
+        assert hasattr(ds, 'SomeVariableName')
+        assert 42 == ds.SomeVariableName
+
+    def test_membership(self):
+        """Dataset: can test if item present by 'if <name> in dataset'."""
+        assert 'TreatmentMachineName' in self.ds
+        assert 'Dummyname' not in self.ds
 
     def test_contains(self):
-        """Dataset: can test if item present by 'if <tag> in dataset'......."""
-        ds = self.dummy_dataset()
-        ds.CommandGroupLength = 100  # (0000,0000)
-        assert (0x300a, 0xb2) in ds
-        assert [0x300a, 0xb2] in ds
-        assert 0x300a00b2 in ds
-        assert (0x10, 0x5f) not in ds
-        assert 'CommandGroupLength' in ds
+        """Dataset: can test if item present by 'if <tag> in dataset'."""
+        self.ds.CommandGroupLength = 100  # (0000,0000)
+        assert (0x300a, 0xb2) in self.ds
+        assert [0x300a, 0xb2] in self.ds
+        assert 0x300a00b2 in self.ds
+        assert (0x10, 0x5f) not in self.ds
+        assert 'CommandGroupLength' in self.ds
         # Use a negative tag to cause an exception
-        assert (-0x0010, 0x0010) not in ds
+        assert (-0x0010, 0x0010) not in self.ds
         # Random non-existent property
-        assert 'random name' not in ds
+        assert 'random name' not in self.ds
 
     def test_clear(self):
-        ds = self.dummy_dataset()
-        assert 1 == len(ds)
-        ds.clear()
-        assert 0 == len(ds)
+        assert 1 == len(self.ds)
+        self.ds.clear()
+        assert 0 == len(self.ds)
 
     def test_pop(self):
-        ds = self.dummy_dataset()
         with pytest.raises(KeyError):
-            ds.pop(0x300a00b244)
-        assert 'default' == ds.pop('dummy', 'default')
-        elem = ds.pop(0x300a00b2)
+            self.ds.pop(0x300a00b244)
+        assert 'default' == self.ds.pop('dummy', 'default')
+        elem = self.ds.pop(0x300a00b2)
         assert 'unit001' == elem.value
         with pytest.raises(KeyError):
-            ds.pop(0x300a00b2)
+            self.ds.pop(0x300a00b2)
 
     def test_pop_using_tuple(self):
-        ds = self.dummy_dataset()
-        elem = ds.pop((0x300a, 0x00b2))
+        elem = self.ds.pop((0x300a, 0x00b2))
         assert 'unit001' == elem.value
         with pytest.raises(KeyError):
-            ds.pop((0x300a, 0x00b2))
+            self.ds.pop((0x300a, 0x00b2))
 
     def test_pop_using_keyword(self):
-        ds = self.dummy_dataset()
         with pytest.raises(KeyError):
-            ds.pop('InvalidName')
-        elem = ds.pop('TreatmentMachineName')
+            self.ds.pop('InvalidName')
+        elem = self.ds.pop('TreatmentMachineName')
         assert 'unit001' == elem.value
         with pytest.raises(KeyError):
-            ds.pop('TreatmentMachineName')
+            self.ds.pop('TreatmentMachineName')
 
     def test_popitem(self):
-        ds = self.dummy_dataset()
-        elem = ds.popitem()
+        elem = self.ds.popitem()
         assert 0x300a00b2 == elem[0]
         assert 'unit001' == elem[1].value
         with pytest.raises(KeyError):
-            ds.popitem()
+            self.ds.popitem()
 
     def test_setdefault(self):
-        ds = self.dummy_dataset()
-        elem = ds.setdefault(0x300a00b2, 'foo')
+        elem = self.ds.setdefault(0x300a00b2, 'foo')
         assert 'unit001' == elem.value
-        elem = ds.setdefault(0x00100010, DataElement(0x00100010, 'PN', "Test"))
-        assert elem.value == 'Test'
-        assert 2 == len(ds)
+        elem = self.ds.setdefault(
+            0x00100010, DataElement(0x00100010, 'PN', "Test")
+        )
+        assert 'Test' == elem.value
+        assert 2 == len(self.ds)
 
     def test_setdefault_tuple(self):
-        ds = self.dummy_dataset()
-        elem = ds.setdefault((0x300a, 0x00b2), 'foo')
+        elem = self.ds.setdefault((0x300a, 0x00b2), 'foo')
         assert 'unit001' == elem.value
-        elem = ds.setdefault((0x0010, 0x0010), DataElement(
-            0x00100010, 'PN', "Test"))
-        assert elem.value == 'Test'
-        assert 2 == len(ds)
+        elem = self.ds.setdefault(
+            (0x0010, 0x0010), DataElement(0x00100010, 'PN', "Test")
+        )
+        assert 'Test' == elem.value
+        assert 2 == len(self.ds)
 
     def test_setdefault_use_value(self):
-        ds = self.dummy_dataset()
-        elem = ds.setdefault((0x0010, 0x0010), "Test")
-        assert elem.value == 'Test'
-        assert 2 == len(ds)
+        elem = self.ds.setdefault((0x0010, 0x0010), "Test")
+        assert 'Test' == elem.value
+        assert 2 == len(self.ds)
         with pytest.raises(KeyError, match=r'Tag \(0011, 0010\) not found '
                                            r'in DICOM dictionary'):
-            ds.setdefault((0x0011, 0x0010), "Test")
+            self.ds.setdefault((0x0011, 0x0010), "Test")
 
     def test_setdefault_keyword(self):
-        ds = self.dummy_dataset()
-        elem = ds.setdefault('TreatmentMachineName', 'foo')
+        elem = self.ds.setdefault('TreatmentMachineName', 'foo')
         assert 'unit001' == elem.value
-        elem = ds.setdefault('PatientName',
-                             DataElement(0x00100010, 'PN', "Test"))
-        assert elem.value == 'Test'
-        assert 2 == len(ds)
-
-    def testGetExists1(self):
-        """Dataset: dataset.get() returns an existing item by name.........."""
-        ds = self.dummy_dataset()
-        unit = ds.get('TreatmentMachineName', None)
-        self.assertEqual(
-            'unit001', unit,
-            "dataset.get() did not return existing member by name")
-
-    def testGetExists2(self):
-        """Dataset: dataset.get() returns an existing item by long tag......"""
-        ds = self.dummy_dataset()
-        unit = ds.get(0x300A00B2, None).value
-        self.assertEqual(
-            unit,
-            'unit001',
-            "dataset.get() did not return existing member by long tag")
-
-    def testGetExists3(self):
-        """Dataset: dataset.get() returns an existing item by tuple tag....."""
-        ds = self.dummy_dataset()
-        unit = ds.get((0x300A, 0x00B2), None).value
-        self.assertEqual(
-            unit,
-            'unit001',
-            "dataset.get() did not return existing member by tuple tag")
-
-    def testGetExists4(self):
-        """Dataset: dataset.get() returns an existing item by Tag..........."""
-        ds = self.dummy_dataset()
-        unit = ds.get(Tag(0x300A00B2), None).value
-        self.assertEqual(
-            unit,
-            'unit001',
-            "dataset.get() did not return existing member by tuple tag")
-
-    def testGetDefault1(self):
-        """Dataset: dataset.get() returns default for non-existing name ...."""
-        ds = self.dummy_dataset()
-        not_there = ds.get('NotAMember', "not-there")
-        msg = ("dataset.get() did not return default value "
-               "for non-member by name")
-
-        self.assertEqual(not_there, "not-there", msg)
-
-    def testGetDefault2(self):
+        elem = self.ds.setdefault(
+            'PatientName', DataElement(0x00100010, 'PN', "Test")
+        )
+        assert 'Test' == elem.value
+        assert 2 == len(self.ds)
+
+    def test_get_exists1(self):
+        """Dataset: dataset.get() returns an existing item by name."""
+        assert 'unit001' == self.ds.get('TreatmentMachineName', None)
+
+    def test_get_exists2(self):
+        """Dataset: dataset.get() returns an existing item by long tag."""
+        assert 'unit001' == self.ds.get(0x300A00B2, None).value
+
+    def test_get_exists3(self):
+        """Dataset: dataset.get() returns an existing item by tuple tag."""
+        assert 'unit001' == self.ds.get((0x300A, 0x00B2), None).value
+
+    def test_get_exists4(self):
+        """Dataset: dataset.get() returns an existing item by Tag."""
+        assert 'unit001' == self.ds.get(Tag(0x300A00B2), None).value
+
+    def test_get_default1(self):
+        """Dataset: dataset.get() returns default for non-existing name."""
+        assert "not-there" == self.ds.get('NotAMember', "not-there")
+
+    def test_get_default2(self):
         """Dataset: dataset.get() returns default for non-existing tuple tag"""
-        ds = self.dummy_dataset()
-        not_there = ds.get((0x9999, 0x9999), "not-there")
-        msg = ("dataset.get() did not return default value"
-               " for non-member by tuple tag")
-        self.assertEqual(not_there, "not-there", msg)
+        assert "not-there" == self.ds.get((0x9999, 0x9999), "not-there")
 
-    def testGetDefault3(self):
+    def test_get_default3(self):
         """Dataset: dataset.get() returns default for non-existing long tag."""
-        ds = self.dummy_dataset()
-        not_there = ds.get(0x99999999, "not-there")
-        msg = ("dataset.get() did not return default value"
-               " for non-member by long tag")
-        self.assertEqual(not_there, "not-there", msg)
-
-    def testGetDefault4(self):
-        """Dataset: dataset.get() returns default for non-existing Tag......"""
-        ds = self.dummy_dataset()
-        not_there = ds.get(Tag(0x99999999), "not-there")
-        msg = ("dataset.get() did not return default value"
-               " for non-member by Tag")
-        self.assertEqual(not_there, "not-there", msg)
+        assert "not-there" == self.ds.get(0x99999999, "not-there")
+
+    def test_get_default4(self):
+        """Dataset: dataset.get() returns default for non-existing Tag."""
+        assert "not-there" == self.ds.get(Tag(0x99999999), "not-there")
 
     def test_get_raises(self):
         """Test Dataset.get() raises exception when invalid Tag"""
-        ds = self.dummy_dataset()
         with pytest.raises(TypeError,
-                           match='Dataset.get key must be a string or tag'):
-            ds.get(-0x0010, 0x0010)
+                           match=r'Dataset.get key must be a string or tag'):
+            self.ds.get(-0x0010, 0x0010)
 
-    def testGetFromRaw(self):
+    def test_get_from_raw(self):
         """Dataset: get(tag) returns same object as ds[tag] for raw element."""
         # This came from issue 88, where get(tag#) returned a RawDataElement,
         #     while get(name) converted to a true DataElement
@@ -377,49 +292,32 @@ class DatasetTests(unittest.TestCase):
         test_elem = RawDataElement(Tag(test_tag), 'PN', 4, b'test',
                                    0, True, True)
         ds = Dataset({Tag(test_tag): test_elem})
-        by_get = ds.get(test_tag)
-        by_item = ds[test_tag]
-
-        msg = ("Dataset.get() returned different "
-               "objects for ds.get(tag) "
-               "and ds[tag]:\nBy get():%r\nBy ds[tag]:%r\n")
-        self.assertEqual(by_get, by_item, msg % (by_get, by_item))
+        assert ds[test_tag] == ds.get(test_tag)
 
     def test__setitem__(self):
-        """Dataset: if set an item, it must be a DataElement instance......."""
-        def callSet():
-            # common error - set data_element instead of data_element.value
-            ds[0x300a, 0xb2] = "unit1"
-
+        """Dataset: if set an item, it must be a DataElement instance."""
         ds = Dataset()
-        self.assertRaises(TypeError, callSet)
+        with pytest.raises(TypeError):
+            ds[0x300a, 0xb2] = "unit1"
 
     def test_matching_tags(self):
-        """Dataset: key and data_element.tag mismatch raises ValueError....."""
-        def set_wrong_tag():
-            ds[0x10, 0x10] = data_element
+        """Dataset: key and data_element.tag mismatch raises ValueError."""
         ds = Dataset()
         data_element = DataElement((0x300a, 0x00b2), "SH", "unit001")
-        self.assertRaises(ValueError, set_wrong_tag)
-
-    def test_NamedMemberUpdated(self):
-        """Dataset: if set data_element by tag, name also reflects change..."""
-        ds = self.dummy_dataset()
-        ds[0x300a, 0xb2].value = "moon_unit"
-        self.assertEqual(ds.TreatmentMachineName, 'moon_unit',
-                         "Member not updated")
-
-    def testUpdate(self):
-        """Dataset: update() method works with tag or name.................."""
-        ds = self.dummy_dataset()
+        with pytest.raises(ValueError):
+            ds[0x10, 0x10] = data_element
+
+    def test_named_member_updated(self):
+        """Dataset: if set data_element by tag, name also reflects change."""
+        self.ds[0x300a, 0xb2].value = "moon_unit"
+        assert 'moon_unit' == self.ds.TreatmentMachineName
+
+    def test_update(self):
+        """Dataset: update() method works with tag or name."""
         pat_data_element = DataElement((0x10, 0x12), 'PN', 'Johnny')
-        ds.update({'PatientName': 'John', (0x10, 0x12): pat_data_element})
-        self.assertEqual(ds[0x10, 0x10].value, 'John',
-                         "named data_element not set")
-        self.assertEqual(
-            ds[0x10, 0x12].value,
-            'Johnny',
-            "set by tag failed")
+        self.ds.update({'PatientName': 'John', (0x10, 0x12): pat_data_element})
+        assert 'John' == self.ds[0x10, 0x10].value
+        assert 'Johnny' == self.ds[0x10, 0x12].value
 
     def test_dir_subclass(self):
         """Dataset.__dir__ returns class specific dir"""
@@ -439,7 +337,7 @@ class DatasetTests(unittest.TestCase):
 
     def test_dir(self):
         """Dataset.dir() returns sorted list of named data_elements."""
-        ds = self.dummy_dataset()
+        ds = self.ds
         ds.PatientName = "name"
         ds.PatientID = "id"
         ds.NonDicomVariable = "junk"
@@ -449,11 +347,11 @@ class DatasetTests(unittest.TestCase):
                     'PatientName',
                     'TreatmentMachineName',
                     'XRayTubeCurrent']
-        assert ds.dir() == expected
+        assert expected == ds.dir()
 
     def test_dir_filter(self):
         """Test Dataset.dir(*filters) works OK."""
-        ds = self.dummy_dataset()
+        ds = self.ds
         ds.PatientName = "name"
         ds.PatientID = "id"
         ds.NonDicomVariable = "junk"
@@ -464,62 +362,50 @@ class DatasetTests(unittest.TestCase):
         assert 'TreatmentMachineName' in ds
         assert 'PatientName' in ds
         assert 'PatientBirthDate' not in ds
-        assert ds.dir('Patient') == ['PatientID', 'PatientName']
-        assert ds.dir('Name') == ['PatientName', 'TreatmentMachineName']
-        assert ds.dir('Name', 'Patient') == ['PatientID', 'PatientName',
-                                             'TreatmentMachineName']
-
-    def testDeleteDicomAttr(self):
-        """Dataset: delete DICOM attribute by name.........................."""
-        def testAttribute():
-            ds.TreatmentMachineName
-
-        ds = self.dummy_dataset()
-        del ds.TreatmentMachineName
-        self.assertRaises(AttributeError, testAttribute)
-
-    def testDeleteDicomCommandGroupLength(self):
-        """Dataset: delete CommandGroupLength doesn't raise AttributeError.."""
-        def testAttribute():
-            ds.CommandGroupLength
-
-        ds = self.dummy_dataset()
-        ds.CommandGroupLength = 100  # (0x0000, 0x0000)
-        del ds.CommandGroupLength
-        self.assertRaises(AttributeError, testAttribute)
-
-    def testDeleteOtherAttr(self):
-        """Dataset: delete non-DICOM attribute by name......................"""
-        ds = self.dummy_dataset()
-        ds.meaningoflife = 42
-        del ds.meaningoflife
-
-    def testDeleteDicomAttrWeDontHave(self):
-        """Dataset: try delete of missing DICOM attribute..................."""
-        def try_delete():
-            del ds.PatientName
-        ds = self.dummy_dataset()
-        self.assertRaises(AttributeError, try_delete)
-
-    def testDeleteItemLong(self):
-        """Dataset: delete item by tag number (long)..................."""
-        ds = self.dummy_dataset()
-        del ds[0x300a00b2]
-
-    def testDeleteItemTuple(self):
-        """Dataset: delete item by tag number (tuple).................."""
-        ds = self.dummy_dataset()
-        del ds[0x300a, 0x00b2]
-
-    def testDeleteNonExistingItem(self):
-        """Dataset: raise KeyError for non-existing item delete........"""
-        ds = self.dummy_dataset()
-
-        def try_delete():
-            del ds[0x10, 0x10]
-        self.assertRaises(KeyError, try_delete)
-
-    def testEqualityNoSequence(self):
+        assert ['PatientID', 'PatientName'] == ds.dir('Patient')
+        assert ['PatientName', 'TreatmentMachineName'] == ds.dir('Name')
+        expected = ['PatientID', 'PatientName', 'TreatmentMachineName']
+        assert expected == ds.dir('Name', 'Patient')
+
+    def test_delete_dicom_attr(self):
+        """Dataset: delete DICOM attribute by name."""
+        del self.ds.TreatmentMachineName
+        with pytest.raises(AttributeError):
+            self.ds.TreatmentMachineName
+
+    def test_delete_dicom_command_group_length(self):
+        """Dataset: delete CommandGroupLength doesn't raise AttributeError."""
+        self.ds.CommandGroupLength = 100  # (0x0000, 0x0000)
+        del self.ds.CommandGroupLength
+        with pytest.raises(AttributeError):
+            self.ds.CommandGroupLength
+
+    def test_delete_other_attr(self):
+        """Dataset: delete non-DICOM attribute by name."""
+        self.ds.meaningoflife = 42
+        assert hasattr(self.ds, 'meaningoflife')
+        del self.ds.meaningoflife
+        assert not hasattr(self.ds, 'meaningoflife')
+
+    def test_delete_dicom_attr_we_dont_have(self):
+        """Dataset: try delete of missing DICOM attribute."""
+        with pytest.raises(AttributeError):
+            del self.ds.PatientName
+
+    def test_delete_item_long(self):
+        """Dataset: delete item by tag number (long)."""
+        del self.ds[0x300a00b2]
+
+    def test_delete_item_tuple(self):
+        """Dataset: delete item by tag number (tuple)."""
+        del self.ds[0x300a, 0x00b2]
+
+    def test_delete_non_existing_item(self):
+        """Dataset: raise KeyError for non-existing item delete."""
+        with pytest.raises(KeyError):
+            del self.ds[0x10, 0x10]
+
+    def test_equality_no_sequence(self):
         """Dataset: equality returns correct value with simple dataset"""
         # Test empty dataset
         assert Dataset() == Dataset()
@@ -560,25 +446,24 @@ class DatasetTests(unittest.TestCase):
         e.SOPInstanceUID = '1.2.3.4'
         assert not d == e
 
-    def testEqualityPrivate(self):
+    def test_equality_private(self):
         """Dataset: equality returns correct value"""
         """when dataset has private elements"""
         d = Dataset()
         d_elem = DataElement(0x01110001, 'PN', 'Private')
-        self.assertTrue(d == d)
+        assert d == d
         d.add(d_elem)
 
         e = Dataset()
         e_elem = DataElement(0x01110001, 'PN', 'Private')
         e.add(e_elem)
-        self.assertTrue(d == e)
+        assert e == d
 
         e[0x01110001].value = 'Public'
-        self.assertFalse(d == e)
+        assert not e == d
 
-    def testEqualitySequence(self):
-        """Dataset: equality returns correct value"""
-        """when dataset has sequences"""
+    def test_equality_sequence(self):
+        """Equality returns correct value with sequences"""
         # Test even sequences
         d = Dataset()
         d.SOPInstanceUID = '1.2.3.4'
@@ -587,7 +472,7 @@ class DatasetTests(unittest.TestCase):
         beam_seq.PatientID = '1234'
         beam_seq.PatientName = 'ANON'
         d.BeamSequence.append(beam_seq)
-        self.assertTrue(d == d)
+        assert d == d
 
         e = Dataset()
         e.SOPInstanceUID = '1.2.3.4'
@@ -596,30 +481,31 @@ class DatasetTests(unittest.TestCase):
         beam_seq.PatientName = 'ANON'
         beam_seq.PatientID = '1234'
         e.BeamSequence.append(beam_seq)
-        self.assertTrue(d == e)
+        assert d == e
 
         e.BeamSequence[0].PatientName = 'ANONY'
-        self.assertFalse(d == e)
+        assert not d == e
 
         # Test uneven sequences
         e.BeamSequence[0].PatientName = 'ANON'
-        self.assertTrue(d == e)
+        assert d == e
 
         e.BeamSequence.append(beam_seq)
-        self.assertFalse(d == e)
+        assert not d == e
 
         d.BeamSequence.append(beam_seq)
-        self.assertTrue(d == e)
+        assert d == e
         d.BeamSequence.append(beam_seq)
-        self.assertFalse(d == e)
+        assert not d == e
 
-    def testEqualityNotDataset(self):
+    def test_equality_not_dataset(self):
         """Dataset: equality returns correct value when not the same class"""
         d = Dataset()
         d.SOPInstanceUID = '1.2.3.4'
-        self.assertFalse(d == {'SOPInstanceUID': '1.2.3.4'})
+        # Make sure Dataset.__eq__() is being used, not dict__eq__()
+        assert not d == {'SOPInstanceUID': '1.2.3.4'}
 
-    def testEqualityUnknown(self):
+    def test_equality_unknown(self):
         """Dataset: equality returns correct value with extra members """
         # Non-element class members are ignored in equality testing
         d = Dataset()
@@ -630,7 +516,7 @@ class DatasetTests(unittest.TestCase):
         e.SOPEustaceUID = '1.2.3.5'
         assert d == e
 
-    def testEqualityInheritance(self):
+    def test_equality_inheritance(self):
         """Dataset: equality returns correct value for subclass """
 
         class DatasetPlus(Dataset):
@@ -640,13 +526,13 @@ class DatasetTests(unittest.TestCase):
         d.PatientName = 'ANON'
         e = DatasetPlus()
         e.PatientName = 'ANON'
-        self.assertTrue(d == e)
-        self.assertTrue(e == d)
-        self.assertTrue(e == e)
+        assert d == e
+        assert e == d
+        assert e == e
 
         e.PatientName = 'ANONY'
-        self.assertFalse(d == e)
-        self.assertFalse(e == d)
+        assert not d == e
+        assert not e == d
 
     def test_equality_elements(self):
         """Test that Dataset equality only checks DataElements."""
@@ -665,21 +551,18 @@ class DatasetTests(unittest.TestCase):
         """Test inequality operator"""
         d = Dataset()
         d.SOPInstanceUID = '1.2.3.4'
-        self.assertFalse(d != d)
+        assert not d != d
 
         e = Dataset()
         e.SOPInstanceUID = '1.2.3.5'
-        self.assertTrue(d != e)
+        assert d != e
 
-    def testHash(self):
+    def test_hash(self):
         """DataElement: hash returns TypeError"""
-
-        def test_hash():
-            d = Dataset()
-            d.PatientName = 'ANON'
-            hash(d)
-
-        self.assertRaises(TypeError, test_hash)
+        ds = Dataset()
+        ds.PatientName = 'ANON'
+        with pytest.raises(TypeError):
+            hash(ds)
 
     def test_property(self):
         """Test properties work OK."""
@@ -694,39 +577,42 @@ class DatasetTests(unittest.TestCase):
 
         dsp = DSPlus()
         dsp.test = 'ABCD'
-        self.assertEqual(dsp.test, 'ABCD')
+        assert 'ABCD' == dsp.test
 
     def test_add_repeater_elem_by_keyword(self):
-        """Repeater using keyword to add repeater"""
-        """group elements raises ValueError."""
+        """Repeater using keyword to add repeater group elements raises."""
         ds = Dataset()
-
-        def test():
+        with pytest.raises(ValueError):
             ds.OverlayData = b'\x00'
-        self.assertRaises(ValueError, test)
 
     def test_setitem_slice_raises(self):
         """Test Dataset.__setitem__ raises if slicing used."""
         ds = Dataset()
-        self.assertRaises(NotImplementedError, ds.__setitem__,
-                          slice(None), Dataset())
+        with pytest.raises(NotImplementedError):
+            ds.__setitem__(slice(None), Dataset())
 
     def test_getitem_slice_raises(self):
         """Test Dataset.__getitem__ raises if slice Tags invalid."""
         ds = Dataset()
-        self.assertRaises(ValueError, ds.__getitem__, slice(None, -1))
-        self.assertRaises(ValueError, ds.__getitem__, slice(-1, -1))
-        self.assertRaises(ValueError, ds.__getitem__, slice(-1))
+        with pytest.raises(ValueError):
+            ds.__getitem__(slice(None, -1))
+        with pytest.raises(ValueError):
+            ds.__getitem__(slice(-1, -1))
+        with pytest.raises(ValueError):
+            ds.__getitem__(slice(-1))
 
     def test_empty_slice(self):
         """Test Dataset slicing with empty Dataset."""
         ds = Dataset()
-        self.assertEqual(ds[:], Dataset())
-        self.assertRaises(ValueError, ds.__getitem__, slice(None, -1))
-        self.assertRaises(ValueError, ds.__getitem__, slice(-1, -1))
-        self.assertRaises(ValueError, ds.__getitem__, slice(-1))
-        self.assertRaises(NotImplementedError, ds.__setitem__,
-                          slice(None), Dataset())
+        assert ds[:] == Dataset()
+        with pytest.raises(ValueError):
+            ds.__getitem__(slice(None, -1))
+        with pytest.raises(ValueError):
+            ds.__getitem__(slice(-1, -1))
+        with pytest.raises(ValueError):
+            ds.__getitem__(slice(-1))
+        with pytest.raises(NotImplementedError):
+            ds.__setitem__(slice(None), Dataset())
 
     def test_getitem_slice(self):
         """Test Dataset.__getitem__ using slices."""
@@ -754,65 +640,60 @@ class DatasetTests(unittest.TestCase):
         ds.BeamSequence[0].PatientName = 'ANON'
 
         # Slice all items - should return original dataset
-        self.assertEqual(ds[:], ds)
+        assert ds[:] == ds
 
         # Slice starting from and including (0008,0001)
         test_ds = ds[0x00080001:]
-        self.assertFalse('CommandGroupLength' in test_ds)
-        self.assertFalse('CommandLengthToEnd' in test_ds)
-        self.assertFalse('Overlays' in test_ds)
-        self.assertTrue('LengthToEnd' in test_ds)
-        self.assertTrue('BeamSequence' in test_ds)
+        assert 'CommandGroupLength' not in test_ds
+        assert 'CommandLengthToEnd' not in test_ds
+        assert 'Overlays' not in test_ds
+        assert 'LengthToEnd' in test_ds
+        assert 'BeamSequence' in test_ds
 
         # Slice ending at and not including (0009,0002)
         test_ds = ds[:0x00090002]
-        self.assertTrue('CommandGroupLength' in test_ds)
-        self.assertTrue('CommandLengthToEnd' in test_ds)
-        self.assertTrue('Overlays' in test_ds)
-        self.assertTrue('LengthToEnd' in test_ds)
-        self.assertTrue(0x00090001 in test_ds)
-        self.assertFalse(0x00090002 in test_ds)
-        self.assertFalse('BeamSequence' in test_ds)
+        assert 'CommandGroupLength' in test_ds
+        assert 'CommandLengthToEnd' in test_ds
+        assert 'Overlays' in test_ds
+        assert 'LengthToEnd' in test_ds
+        assert 0x00090001 in test_ds
+        assert 0x00090002 not in test_ds
+        assert 'BeamSequence' not in test_ds
 
         # Slice with a step - every second tag
         # Should return zeroth tag, then second, fourth, etc...
         test_ds = ds[::2]
-        self.assertTrue('CommandGroupLength' in test_ds)
-        self.assertFalse('CommandLengthToEnd' in test_ds)
-        self.assertTrue(0x00090001 in test_ds)
-        self.assertFalse(0x00090002 in test_ds)
+        assert 'CommandGroupLength' in test_ds
+        assert 'CommandLengthToEnd' not in test_ds
+        assert 0x00090001 in test_ds
+        assert 0x00090002 not in test_ds
 
         # Slice starting at and including (0008,0018) and ending at and not
         #   including (0009,0008)
         test_ds = ds[0x00080018:0x00090008]
-        self.assertTrue('SOPInstanceUID' in test_ds)
-        self.assertTrue(0x00090007 in test_ds)
-        self.assertFalse(0x00090008 in test_ds)
+        assert 'SOPInstanceUID' in test_ds
+        assert 0x00090007 in test_ds
+        assert 0x00090008 not in test_ds
 
         # Slice starting at and including (0008,0018) and ending at and not
         #   including (0009,0008), every third element
         test_ds = ds[0x00080018:0x00090008:3]
-        self.assertTrue('SOPInstanceUID' in test_ds)
-        self.assertFalse(0x00090001 in test_ds)
-        self.assertTrue(0x00090002 in test_ds)
-        self.assertFalse(0x00090003 in test_ds)
-        self.assertFalse(0x00090004 in test_ds)
-        self.assertTrue(0x00090005 in test_ds)
-        self.assertFalse(0x00090006 in test_ds)
-        self.assertFalse(0x00090008 in test_ds)
+        assert 'SOPInstanceUID' in test_ds
+        assert 0x00090001 not in test_ds
+        assert 0x00090002 in test_ds
+        assert 0x00090003 not in test_ds
+        assert 0x00090004 not in test_ds
+        assert 0x00090005 in test_ds
+        assert 0x00090006 not in test_ds
+        assert 0x00090008 not in test_ds
 
         # Slice starting and ending (and not including) (0008,0018)
-        self.assertEqual(
-            ds[(0x0008, 0x0018):(0x0008, 0x0018)],
-            Dataset())
+        assert ds[(0x0008, 0x0018):(0x0008, 0x0018)] == Dataset()
 
         # Test slicing using other acceptable Tag initialisations
-        self.assertTrue(
-            'SOPInstanceUID' in ds[(0x00080018):(0x00080019)])
-        self.assertTrue(
-            'SOPInstanceUID' in ds[(0x0008, 0x0018):(0x0008, 0x0019)])
-        self.assertTrue(
-            'SOPInstanceUID' in ds['0x00080018':'0x00080019'])
+        assert 'SOPInstanceUID' in ds[(0x00080018):(0x00080019)]
+        assert 'SOPInstanceUID' in ds[(0x0008, 0x0018):(0x0008, 0x0019)]
+        assert 'SOPInstanceUID' in ds['0x00080018':'0x00080019']
 
     def test_getitem_slice_ffff(self):
         """Test slicing with (FFFF,FFFF)"""
@@ -830,7 +711,7 @@ class DatasetTests(unittest.TestCase):
         ds.add_new(0xFFFFFFFE, 'PN', 'CITIZEN^4')
         ds.add_new(0xFFFFFFFF, 'PN', 'CITIZEN^5')
 
-        assert ds[:][0xFFFFFFFF].value == 'CITIZEN^5'
+        assert 'CITIZEN^5' == ds[:][0xFFFFFFFF].value
         assert 0xFFFFFFFF not in ds[0x1000:0xFFFFFFFF]
         assert 0xFFFFFFFF not in ds[(0x1000):(0xFFFF, 0xFFFF)]
 
@@ -861,10 +742,10 @@ class DatasetTests(unittest.TestCase):
 
         # Delete the 0x0009 group
         del ds[0x00090000:0x00100000]
-        self.assertTrue('SkipFrameRangeFlag' in ds)
-        self.assertFalse(0x00090001 in ds)
-        self.assertFalse(0x00090010 in ds)
-        self.assertTrue('PatientName' in ds)
+        assert 'SkipFrameRangeFlag' in ds
+        assert 0x00090001 not in ds
+        assert 0x00090010 not in ds
+        assert 'PatientName' in ds
 
     @pytest.mark.skipif(not compat.in_py2, reason='Python 2 only iterators')
     def test_iteritems(self):
@@ -911,21 +792,21 @@ class DatasetTests(unittest.TestCase):
 
         # Test getting group 0x0000
         group0000 = ds.group_dataset(0x0000)
-        self.assertTrue('CommandGroupLength' in group0000)
-        self.assertTrue('CommandLengthToEnd' in group0000)
-        self.assertTrue('Overlays' in group0000)
-        self.assertFalse('LengthToEnd' in group0000)
-        self.assertFalse('SOPInstanceUID' in group0000)
-        self.assertFalse('SkipFrameRangeFlag' in group0000)
+        assert 'CommandGroupLength' in group0000
+        assert 'CommandLengthToEnd' in group0000
+        assert 'Overlays' in group0000
+        assert 'LengthToEnd' not in group0000
+        assert 'SOPInstanceUID' not in group0000
+        assert 'SkipFrameRangeFlag' not in group0000
 
         # Test getting group 0x0008
         group0000 = ds.group_dataset(0x0008)
-        self.assertFalse('CommandGroupLength' in group0000)
-        self.assertFalse('CommandLengthToEnd' in group0000)
-        self.assertFalse('Overlays' in group0000)
-        self.assertTrue('LengthToEnd' in group0000)
-        self.assertTrue('SOPInstanceUID' in group0000)
-        self.assertTrue('SkipFrameRangeFlag' in group0000)
+        assert 'CommandGroupLength' not in group0000
+        assert 'CommandLengthToEnd' not in group0000
+        assert 'Overlays' not in group0000
+        assert 'LengthToEnd' in group0000
+        assert 'SOPInstanceUID' in group0000
+        assert 'SkipFrameRangeFlag' in group0000
 
     def test_get_item(self):
         """Test Dataset.get_item"""
@@ -934,17 +815,17 @@ class DatasetTests(unittest.TestCase):
         ds.SOPInstanceUID = '1.2.3.4'  # 0008,0018
 
         # Test non-deferred read
-        assert ds.get_item(0x00000000) == ds[0x00000000]
-        assert ds.get_item(0x00000000).value == 120
-        assert ds.get_item(0x00080018) == ds[0x00080018]
-        assert ds.get_item(0x00080018).value == '1.2.3.4'
+        assert ds[0x00000000] == ds.get_item(0x00000000)
+        assert 120 == ds.get_item(0x00000000).value
+        assert ds[0x00080018] == ds.get_item(0x00080018)
+        assert '1.2.3.4' == ds.get_item(0x00080018).value
 
         # Test deferred read
         test_file = get_testdata_files('MR_small.dcm')[0]
         ds = dcmread(test_file, force=True, defer_size='0.8 kB')
         ds_ref = dcmread(test_file, force=True)
         # get_item will follow the deferred read branch
-        assert ds.get_item((0x7fe00010)).value == ds_ref.PixelData
+        assert ds_ref.PixelData == ds.get_item((0x7fe00010)).value
 
     def test_get_item_slice(self):
         """Test Dataset.get_item with slice argument"""
@@ -1019,8 +900,8 @@ class DatasetTests(unittest.TestCase):
         assert 0x00090006 not in test_ds
 
         # Slice starting and ending (and not including) (0008,0018)
-        assert ds.get_item(slice((0x0008, 0x0018),
-                                 (0x0008, 0x0018))) == Dataset()
+        assert Dataset() == ds.get_item(slice((0x0008, 0x0018),
+                                              (0x0008, 0x0018)))
 
         # Test slicing using other acceptable Tag initialisations
         assert 'SOPInstanceUID' in ds.get_item(slice(0x00080018, 0x00080019))
@@ -1030,7 +911,7 @@ class DatasetTests(unittest.TestCase):
                                                      '0x00080019'))
 
         # Slice all items - should return original dataset
-        assert ds.get_item(slice(None, None)) == ds
+        assert ds == ds.get_item(slice(None, None))
 
     def test_get_private_item(self):
         ds = Dataset()
@@ -1077,6 +958,7 @@ class DatasetTests(unittest.TestCase):
         with pytest.raises(KeyError,
                            match="Private creator 'Creator 3.0' not found"):
             ds.private_block(0x0009, 'Creator 3.0')
+
         block = ds.private_block(0x0009, 'Creator 1.0')
 
         # test for containment
@@ -1089,13 +971,15 @@ class DatasetTests(unittest.TestCase):
         block = ds.private_block(0x0009, 'Creator 2.0')
         with pytest.raises(ValueError,
                            match='Element offset must be less than 256'):
-            _ = block[0x0101]
+            block[0x0101]
+
         item = block[0x01]
         assert 'Version2' == item.value
 
         # Dataset.get_private_item
         with pytest.raises(KeyError):
             ds.get_private_item(0x0009, 0x02, 'Creator 1.0')
+
         item = ds.get_private_item(0x0009, 0x02, 'Creator 2.0')
         assert 2 == item.value
 
@@ -1178,10 +1062,10 @@ class DatasetTests(unittest.TestCase):
         ds.PatientName = 'CITIZEN^Jan'  # 0010,0010
 
         ds.remove_private_tags()
-        self.assertEqual(ds[0x00090000:0x00100000], Dataset())
-        self.assertTrue('CommandGroupLength' in ds)
-        self.assertTrue('SkipFrameRangeFlag' in ds)
-        self.assertTrue('PatientName' in ds)
+        assert Dataset() == ds[0x00090000:0x00100000]
+        assert 'CommandGroupLength' in ds
+        assert 'SkipFrameRangeFlag' in ds
+        assert 'PatientName' in ds
 
     def test_data_element(self):
         """Test Dataset.data_element."""
@@ -1191,8 +1075,8 @@ class DatasetTests(unittest.TestCase):
         ds.add_new(0x00090001, 'PN', 'CITIZEN^1')
         ds.BeamSequence = [Dataset()]
         ds.BeamSequence[0].PatientName = 'ANON'
-        assert ds.data_element('CommandGroupLength') == ds[0x00000000]
-        assert ds.data_element('BeamSequence') == ds[0x300A00B0]
+        assert ds[0x00000000] == ds.data_element('CommandGroupLength')
+        assert ds[0x300A00B0] == ds.data_element('BeamSequence')
         assert ds.data_element('not an element keyword') is None
 
     def test_iterall(self):
@@ -1204,16 +1088,11 @@ class DatasetTests(unittest.TestCase):
         ds.BeamSequence = [Dataset()]
         ds.BeamSequence[0].PatientName = 'ANON'
         elem_gen = ds.iterall()
-        self.assertEqual(
-            ds.data_element('CommandGroupLength'), next(elem_gen))
-        self.assertEqual(
-            ds.data_element('SkipFrameRangeFlag'), next(elem_gen))
-        self.assertEqual(ds[0x00090001], next(elem_gen))
-        self.assertEqual(
-            ds.data_element('BeamSequence'), next(elem_gen))
-        self.assertEqual(
-            ds.BeamSequence[0].data_element('PatientName'),
-            next(elem_gen))
+        assert ds.data_element('CommandGroupLength') == next(elem_gen)
+        assert ds.data_element('SkipFrameRangeFlag') == next(elem_gen)
+        assert ds[0x00090001] == next(elem_gen)
+        assert ds.data_element('BeamSequence') == next(elem_gen)
+        assert ds.BeamSequence[0].data_element('PatientName') == next(elem_gen)
 
     def test_save_as(self):
         """Test Dataset.save_as"""
@@ -1221,24 +1100,18 @@ class DatasetTests(unittest.TestCase):
         ds = Dataset()
         ds.PatientName = 'CITIZEN'
         # Raise AttributeError if is_implicit_VR or is_little_endian missing
-        self.assertRaises(
-            AttributeError,
-            ds.save_as,
-            fp,
-            write_like_original=False)
+        with pytest.raises(AttributeError):
+            ds.save_as(fp, write_like_original=False)
+
         ds.is_implicit_VR = True
-        self.assertRaises(
-            AttributeError,
-            ds.save_as,
-            fp,
-            write_like_original=False)
+        with pytest.raises(AttributeError):
+            ds.save_as(fp, write_like_original=False)
+
         ds.is_little_endian = True
         del ds.is_implicit_VR
-        self.assertRaises(
-            AttributeError,
-            ds.save_as,
-            fp,
-            write_like_original=False)
+        with pytest.raises(AttributeError):
+            ds.save_as(fp, write_like_original=False)
+
         ds.is_implicit_VR = True
         ds.file_meta = Dataset()
         ds.file_meta.MediaStorageSOPClassUID = '1.1'
@@ -1251,7 +1124,7 @@ class DatasetTests(unittest.TestCase):
         """Test Dataset.__enter__ and __exit__."""
         test_file = get_testdata_files('CT_small.dcm')[0]
         with dcmread(test_file) as ds:
-            assert ds.PatientName == 'CompressedSamples^CT1'
+            assert 'CompressedSamples^CT1' == ds.PatientName
 
     def test_exit_exception(self):
         """Test Dataset.__exit__ when an exception is raised."""
@@ -1271,8 +1144,8 @@ class DatasetTests(unittest.TestCase):
         ds._pixel_id = id(ds.PixelData)
         ds._pixel_array = 'Test Value'
         ds.convert_pixel_data()
-        assert ds._pixel_id == id(ds.PixelData)
-        assert ds._pixel_array == 'Test Value'
+        assert id(ds.PixelData) == ds._pixel_id
+        assert 'Test Value' == ds._pixel_array
 
     def test_pixel_array_id_changed(self):
         """Test that we try to get new pixel data if the id has changed."""
@@ -1280,7 +1153,7 @@ class DatasetTests(unittest.TestCase):
         ds = dcmread(fpath)
         ds.file_meta.TransferSyntaxUID = '1.2.3.4'
         ds._pixel_id = 1234
-        assert ds._pixel_id != id(ds.PixelData)
+        assert id(ds.PixelData) != ds._pixel_id
         ds._pixel_array = 'Test Value'
         # If _pixel_id doesn't match then attempt to get new pixel data
         orig_handlers = pydicom.config.pixel_data_handlers
@@ -1317,9 +1190,9 @@ class DatasetTests(unittest.TestCase):
         line_generator = ds.formatted_lines(element_format=elem_format,
                                             sequence_element_format=seq_format,
                                             indent_format=indent_format)
-        assert next(line_generator) == "(0010, 0010)"
-        assert next(line_generator) == "Beam Sequence (300a, 00b0)"
-        assert next(line_generator) == "(0010, 0020)"
+        assert "(0010, 0010)" == next(line_generator)
+        assert "Beam Sequence (300a, 00b0)" == next(line_generator)
+        assert "(0010, 0020)" == next(line_generator)
         with pytest.raises(StopIteration):
             next(line_generator)
 
@@ -1338,8 +1211,8 @@ class DatasetTests(unittest.TestCase):
                               True, True)
         ds.__setitem__((0x0043, 0x1029), elem)
 
-        assert ds[(0x0043, 0x1029)].value == b'\x00\x01'
-        assert type(ds[(0x0043, 0x1029)]) == DataElement
+        assert b'\x00\x01' == ds[(0x0043, 0x1029)].value
+        assert isinstance(ds[(0x0043, 0x1029)], DataElement)
 
     def test_top(self):
         """Test Dataset.top returns only top level str"""
@@ -1374,11 +1247,11 @@ class DatasetTests(unittest.TestCase):
         ds.BeamSequence[1].PatientName = 'Other^Name'
         ds.walk(test_callback, recursive=True)
 
-        assert ds.PatientName == 'CITIZEN^Jan'
-        assert ds.BeamSequence[0].PatientID == 'FIXED'
-        assert ds.BeamSequence[0].PatientName == 'Some^Name'
-        assert ds.BeamSequence[1].PatientID == 'FIXED'
-        assert ds.BeamSequence[1].PatientName == 'Other^Name'
+        assert 'CITIZEN^Jan' == ds.PatientName
+        assert 'FIXED' == ds.BeamSequence[0].PatientID
+        assert 'Some^Name' == ds.BeamSequence[0].PatientName
+        assert 'FIXED' == ds.BeamSequence[1].PatientID
+        assert 'Other^Name' == ds.BeamSequence[1].PatientName
 
     def test_update_with_dataset(self):
         """Regression test for #779"""
@@ -1386,7 +1259,7 @@ class DatasetTests(unittest.TestCase):
         ds.PatientName = "Test"
         ds2 = Dataset()
         ds2.update(ds)
-        assert ds2.PatientName == 'Test'
+        assert 'Test' == ds2.PatientName
 
         # Test sequences
         ds2 = Dataset()
@@ -1395,34 +1268,31 @@ class DatasetTests(unittest.TestCase):
         ds.BeamSequence[1].PatientName = 'TestB'
 
         ds2.update(ds)
-        assert ds2.BeamSequence[0].PatientName == 'TestA'
-        assert ds2.BeamSequence[1].PatientName == 'TestB'
+        assert 'TestA' == ds2.BeamSequence[0].PatientName
+        assert 'TestB' == ds2.BeamSequence[1].PatientName
 
         # Test overwrite
         ds.PatientName = 'TestC'
         ds2.update(ds)
-        assert ds2.PatientName == 'TestC'
+        assert 'TestC' == ds2.PatientName
 
 
-class DatasetElementsTests(unittest.TestCase):
+class TestDatasetElements(object):
     """Test valid assignments of data elements"""
-    def setUp(self):
+    def setup(self):
         self.ds = Dataset()
         self.sub_ds1 = Dataset()
         self.sub_ds2 = Dataset()
 
-    def testSequenceAssignment(self):
-        """Assignment to SQ works only if valid Sequence assigned......"""
-        def try_non_Sequence():
+    def test_sequence_assignment(self):
+        """Assignment to SQ works only if valid Sequence assigned."""
+        msg = r"Sequence contents must be Dataset instances"
+        with pytest.raises(TypeError, match=msg):
             self.ds.ConceptCodeSequence = [1, 2, 3]
-        msg = ("Assigning non-sequence to "
-               "SQ data element did not raise error")
-        self.assertRaises(TypeError, try_non_Sequence, msg=msg)
+
         # check also that assigning proper sequence *does* work
         self.ds.ConceptCodeSequence = [self.sub_ds1, self.sub_ds2]
-        self.assertTrue(
-            isinstance(self.ds.ConceptCodeSequence, Sequence),
-            "Sequence assignment did not result in Sequence type")
+        assert isinstance(self.ds.ConceptCodeSequence, Sequence)
 
     def test_ensure_file_meta(self):
         assert not hasattr(self.ds, 'file_meta')
@@ -1434,12 +1304,12 @@ class DatasetElementsTests(unittest.TestCase):
         self.ds.is_little_endian = True
         self.ds.is_implicit_VR = True
         self.ds.fix_meta_info(enforce_standard=False)
-        assert self.ds.file_meta.TransferSyntaxUID == ImplicitVRLittleEndian
+        assert ImplicitVRLittleEndian == self.ds.file_meta.TransferSyntaxUID
 
         self.ds.is_implicit_VR = False
         self.ds.fix_meta_info(enforce_standard=False)
         # transfer syntax does not change because of ambiguity
-        assert self.ds.file_meta.TransferSyntaxUID == ImplicitVRLittleEndian
+        assert ImplicitVRLittleEndian == self.ds.file_meta.TransferSyntaxUID
 
         self.ds.is_little_endian = False
         self.ds.is_implicit_VR = True
@@ -1448,7 +1318,7 @@ class DatasetElementsTests(unittest.TestCase):
 
         self.ds.is_implicit_VR = False
         self.ds.fix_meta_info(enforce_standard=False)
-        assert self.ds.file_meta.TransferSyntaxUID == ExplicitVRBigEndian
+        assert ExplicitVRBigEndian == self.ds.file_meta.TransferSyntaxUID
 
         assert 'MediaStorageSOPClassUID' not in self.ds.file_meta
         assert 'MediaStorageSOPInstanceUID ' not in self.ds.file_meta
@@ -1459,8 +1329,8 @@ class DatasetElementsTests(unittest.TestCase):
         self.ds.SOPClassUID = '1.2.3'
         self.ds.SOPInstanceUID = '4.5.6'
         self.ds.fix_meta_info(enforce_standard=False)
-        assert self.ds.file_meta.MediaStorageSOPClassUID == '1.2.3'
-        assert self.ds.file_meta.MediaStorageSOPInstanceUID == '4.5.6'
+        assert '1.2.3' == self.ds.file_meta.MediaStorageSOPClassUID
+        assert '4.5.6' == self.ds.file_meta.MediaStorageSOPInstanceUID
         self.ds.fix_meta_info(enforce_standard=True)
 
         self.ds.file_meta.PatientID = 'PatientID'
@@ -1495,40 +1365,40 @@ class DatasetElementsTests(unittest.TestCase):
         validate_file_meta(file_meta, enforce_standard=True)
 
         # check the default created values
-        assert file_meta.FileMetaInformationVersion == b'\x00\x01'
-        assert file_meta.ImplementationClassUID == PYDICOM_IMPLEMENTATION_UID
+        assert b'\x00\x01' == file_meta.FileMetaInformationVersion
+        assert PYDICOM_IMPLEMENTATION_UID == file_meta.ImplementationClassUID
         assert file_meta.ImplementationVersionName.startswith('PYDICOM ')
 
         file_meta.ImplementationClassUID = '1.2.3.4'
         file_meta.ImplementationVersionName = 'ACME LTD'
         validate_file_meta(file_meta, enforce_standard=True)
         # check that existing values are left alone
-        assert file_meta.ImplementationClassUID == '1.2.3.4'
-        assert file_meta.ImplementationVersionName == 'ACME LTD'
+        assert '1.2.3.4' == file_meta.ImplementationClassUID
+        assert 'ACME LTD' == file_meta.ImplementationVersionName
 
 
-class FileDatasetTests(unittest.TestCase):
-    def setUp(self):
+class TestFileDataset(object):
+    def setup(self):
         self.test_file = get_testdata_files('CT_small.dcm')[0]
 
     def test_equality_file_meta(self):
         """Dataset: equality returns correct value if with metadata"""
         d = dcmread(self.test_file)
         e = dcmread(self.test_file)
-        self.assertTrue(d == e)
+        assert d == e
 
         e.is_implicit_VR = not e.is_implicit_VR
-        self.assertFalse(d == e)
+        assert not d == e
 
         e.is_implicit_VR = not e.is_implicit_VR
-        self.assertTrue(d == e)
+        assert d == e
         e.is_little_endian = not e.is_little_endian
-        self.assertFalse(d == e)
+        assert not d == e
 
         e.is_little_endian = not e.is_little_endian
-        self.assertTrue(d == e)
+        assert d == e
         e.filename = 'test_filename.dcm'
-        self.assertFalse(d == e)
+        assert not d == e
 
     def test_creation_with_container(self):
         """FileDataset.__init__ works OK with a container such as gzip"""
@@ -1538,7 +1408,7 @@ class FileDatasetTests(unittest.TestCase):
         ds = Dataset()
         ds.PatientName = "CITIZEN^Jan"
         fds = FileDataset(Dummy(), ds)
-        assert fds.filename == '/some/path/to/test'
+        assert '/some/path/to/test' == fds.filename
 
     def test_works_as_expected_within_numpy_array(self):
         """Test Dataset within a numpy array"""
@@ -1563,8 +1433,3 @@ class FileDatasetTests(unittest.TestCase):
         di = dict()
         expected_diff = {'__class__', '__doc__', '__hash__'}
         assert expected_diff == set(dir(di)) - set(dir(ds))
-
-
-class BadRepr(object):
-    def __repr__(self):
-        raise ValueError("bad repr")
diff --git a/pydicom/tests/test_filereader.py b/pydicom/tests/test_filereader.py
index 3fd7afbbc..142e4fb34 100644
--- a/pydicom/tests/test_filereader.py
+++ b/pydicom/tests/test_filereader.py
@@ -1,6 +1,6 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
 # -*- coding: utf-8 -*-
-"""unittest tests for pydicom.filereader module"""
+"""Unit tests for the pydicom.filereader module."""
 
 import gzip
 from io import BytesIO
@@ -8,7 +8,6 @@ import os
 import shutil
 import sys
 import tempfile
-import unittest
 
 import pytest
 
@@ -25,11 +24,9 @@ from pydicom.tag import Tag, TupleTag
 from pydicom.uid import ImplicitVRLittleEndian
 import pydicom.valuerep
 
-have_gdcm_handler = True
-try:
-    import pydicom.pixel_data_handlers.gdcm_handler as gdcm_handler
-except ImportError as e:
-    have_gdcm_handler = False
+
+from pydicom.pixel_data_handlers import gdcm_handler
+have_gdcm_handler = gdcm_handler.is_available()
 
 try:
     import numpy  # NOQA
@@ -94,27 +91,27 @@ dir_name = os.path.dirname(sys.argv[0])
 save_dir = os.getcwd()
 
 
-class ReaderTests(unittest.TestCase):
-    def testEmptyNumbersTag(self):
+class TestReader(object):
+    def test_empty_numbers_tag(self):
         """Tests that an empty tag with a number VR (FL, UL, SL, US,
         SS, FL, FD, OF) reads as an empty string"""
         empty_number_tags_ds = dcmread(empty_number_tags_name)
-        self.assertEqual(empty_number_tags_ds.ExaminedBodyThickness, '')
-        self.assertEqual(empty_number_tags_ds.SimpleFrameList, '')
-        self.assertEqual(empty_number_tags_ds.ReferencePixelX0, '')
-        self.assertEqual(empty_number_tags_ds.PhysicalUnitsXDirection, '')
-        self.assertEqual(empty_number_tags_ds.TagAngleSecondAxis, '')
-        self.assertEqual(empty_number_tags_ds.TagSpacingSecondDimension, '')
-        self.assertEqual(empty_number_tags_ds.VectorGridData, '')
-
-    def testUTF8FileName(self):
+        assert '' == empty_number_tags_ds.ExaminedBodyThickness
+        assert '' == empty_number_tags_ds.SimpleFrameList
+        assert '' == empty_number_tags_ds.ReferencePixelX0
+        assert '' == empty_number_tags_ds.PhysicalUnitsXDirection
+        assert '' == empty_number_tags_ds.TagAngleSecondAxis
+        assert '' == empty_number_tags_ds.TagSpacingSecondDimension
+        assert '' == empty_number_tags_ds.VectorGridData
+
+    def test_UTF8_filename(self):
         utf8_filename = os.path.join(tempfile.gettempdir(), "ДИКОМ.dcm")
         shutil.copyfile(rtdose_name, utf8_filename)
         ds = dcmread(utf8_filename)
         os.remove(utf8_filename)
-        self.assertTrue(ds is not None)
+        assert ds is not None
 
-    def testRTPlan(self):
+    def test_RTPlan(self):
         """Returns correct values for sample data elements in test
         RT Plan file.
         """
@@ -123,88 +120,68 @@ class ReaderTests(unittest.TestCase):
         # if not two controlpoints, then this would raise exception
         cp0, cp1 = beam.ControlPointSequence
 
-        self.assertEqual(beam.TreatmentMachineName, "unit001",
-                         "Incorrect unit name")
-        self.assertEqual(beam.TreatmentMachineName, beam[0x300a, 0x00b2].value,
-                         "beam TreatmentMachineName does not match "
-                         "the value accessed by tag number")
+        assert "unit001" == beam.TreatmentMachineName
+        assert beam[0x300a, 0x00b2].value == beam.TreatmentMachineName
 
         got = cp1.ReferencedDoseReferenceSequence[
             0].CumulativeDoseReferenceCoefficient
         DS = pydicom.valuerep.DS
         expected = DS('0.9990268')
-        self.assertTrue(got == expected,
-                        "Cum Dose Ref Coeff not the expected value "
-                        "(CP1, Ref'd Dose Ref")
+        assert expected == got
         got = cp0.BeamLimitingDevicePositionSequence[0].LeafJawPositions
-        self.assertTrue(got[0] == DS('-100') and got[1] == DS('100.0'),
-                        "X jaws not as expected (control point 0)")
+        assert [DS('-100'), DS('100.0')] == got
 
-    def testRTDose(self):
+    def test_RTDose(self):
         """Returns correct values for sample data elements in test
         RT Dose file"""
         dose = dcmread(rtdose_name)
-        self.assertEqual(dose.FrameIncrementPointer, Tag((0x3004, 0x000c)),
-                         "Frame Increment Pointer not the expected value")
-        self.assertEqual(dose.FrameIncrementPointer, dose[0x28, 9].value,
-                         "FrameIncrementPointer does not match the value "
-                         "accessed by tag number")
+        assert Tag((0x3004, 0x000c)) == dose.FrameIncrementPointer
+        assert dose[0x28, 9].value == dose.FrameIncrementPointer
 
         # try a value that is nested the deepest
         # (so deep I break it into two steps!)
-        fract = \
+        fract = (
             dose.ReferencedRTPlanSequence[0].ReferencedFractionGroupSequence[0]
-        beamnum = fract.ReferencedBeamSequence[0].ReferencedBeamNumber
-        self.assertEqual(beamnum, 1, "Beam number not the expected value")
+        )
+        assert 1 == fract.ReferencedBeamSequence[0].ReferencedBeamNumber
 
-    def testCT(self):
+    def test_CT(self):
         """Returns correct values for sample data elements in test CT file."""
         ct = dcmread(ct_name)
-        self.assertEqual(ct.file_meta.ImplementationClassUID,
-                         '1.3.6.1.4.1.5962.2',
-                         "ImplementationClassUID not the expected value")
-        self.assertEqual(ct.file_meta.ImplementationClassUID,
-                         ct.file_meta[0x2, 0x12].value,
-                         "ImplementationClassUID does not match the value "
-                         "accessed by tag number")
+        assert '1.3.6.1.4.1.5962.2' == ct.file_meta.ImplementationClassUID
+        value = ct.file_meta[0x2, 0x12].value
+        assert value == ct.file_meta.ImplementationClassUID
+
         # (0020, 0032) Image Position (Patient)
         # [-158.13580300000001, -179.035797, -75.699996999999996]
         got = ct.ImagePositionPatient
         DS = pydicom.valuerep.DS
         expected = [DS('-158.135803'), DS('-179.035797'), DS('-75.699997')]
-        self.assertTrue(got == expected,
-                        "ImagePosition(Patient) values not as expected."
-                        "got {0}, expected {1}".format(got, expected))
+        assert expected == got
 
-        self.assertEqual(ct.Rows, 128, "Rows not 128")
-        self.assertEqual(ct.Columns, 128, "Columns not 128")
-        self.assertEqual(ct.BitsStored, 16, "Bits Stored not 16")
-        self.assertEqual(len(ct.PixelData), 128 * 128 * 2,
-                         "Pixel data not expected length")
+        assert 128 == ct.Rows
+        assert 128 == ct.Columns
+        assert 16 == ct.BitsStored
+        assert 128 * 128 * 2 == len(ct.PixelData)
 
         # Also test private elements name can be resolved:
-        expected = "[Duration of X-ray on]"
         got = ct[(0x0043, 0x104e)].name
-        msg = "Mismatch in private tag name, expected '%s', got '%s'"
-        self.assertEqual(expected, got, msg % (expected, got))
+        assert "[Duration of X-ray on]" == got
 
-    @unittest.skipUnless(have_numpy, "Numpy not installed")
-    def testCTPixelData(self):
+    @pytest.mark.skipif(not have_numpy, reason="Numpy not installed")
+    def test_CT_PixelData(self):
         """Check that we can read pixel data.
         Tests that we get last one in array.
         """
         ct = dcmread(ct_name)
-        expected = 909
-        got = ct.pixel_array[-1][-1]
-        msg = ("Did not get correct value for last pixel: "
-               "expected %d, got %r" % (expected, got))
-        self.assertEqual(expected, got, msg)
+        assert 909 == ct.pixel_array[-1][-1]
 
-    def testNoForce(self):
+    def test_no_force(self):
         """Raises exception if missing DICOM header and force==False."""
-        self.assertRaises(InvalidDicomError, dcmread, rtstruct_name)
+        with pytest.raises(InvalidDicomError):
+            dcmread(rtstruct_name)
 
-    def testRTstruct(self):
+    def test_RTStruct(self):
         """Returns correct values for sample elements in test RTSTRUCT file."""
         # RTSTRUCT test file has complex nested sequences
         # -- see rtstruct.dump file
@@ -214,22 +191,16 @@ class ReaderTests(unittest.TestCase):
         frame_of_ref = rtss.ReferencedFrameOfReferenceSequence[0]
         study = frame_of_ref.RTReferencedStudySequence[0]
         uid = study.RTReferencedSeriesSequence[0].SeriesInstanceUID
-        expected = "1.2.826.0.1.3680043.8.498.2010020400001.2.1.1"
-        msg = "Expected Reference Series UID '%s', got '%s'" % (expected, uid)
-        self.assertEqual(expected, uid, msg)
+        assert "1.2.826.0.1.3680043.8.498.2010020400001.2.1.1" == uid
 
         got = rtss.ROIContourSequence[0].ContourSequence[2].ContourNumber
-        expected = 3
-        msg = "Expected Contour Number %d, got %r" % (expected, got)
-        self.assertEqual(expected, got, msg)
+        assert 3 == got
 
         obs_seq0 = rtss.RTROIObservationsSequence[0]
         got = obs_seq0.ROIPhysicalPropertiesSequence[0].ROIPhysicalProperty
-        expected = 'REL_ELEC_DENSITY'
-        msg = "Expected Physical Property '%s', got %r" % (expected, got)
-        self.assertEqual(expected, got, msg)
+        assert 'REL_ELEC_DENSITY' == got
 
-    def testDir(self):
+    def test_dir(self):
         """Returns correct dir attributes for both Dataset and DICOM names
         (python >= 2.6).."""
         # Only python >= 2.6 calls __dir__ for dir() call
@@ -239,8 +210,7 @@ class ReaderTests(unittest.TestCase):
         expect_in_dir = ['pixel_array', 'add_new', 'ROIContourSequence',
                          'StructureSetDate']
         for name in expect_in_dir:
-            self.assertTrue(name in got_dir,
-                            "Expected name '%s' in dir()" % name)
+            assert name in got_dir
 
         # Now check for some items in dir() of a nested item
         roi0 = rtss.ROIContourSequence[0]
@@ -248,39 +218,29 @@ class ReaderTests(unittest.TestCase):
         expect_in_dir = ['pixel_array', 'add_new', 'ReferencedROINumber',
                          'ROIDisplayColor']
         for name in expect_in_dir:
-            self.assertTrue(name in got_dir,
-                            "Expected name '%s' in dir()" % name)
+            assert name in got_dir
 
-    def testMR(self):
+    def test_MR(self):
         """Returns correct values for sample data elements in test MR file."""
         mr = dcmread(mr_name)
         # (0010, 0010) Patient's Name           'CompressedSamples^MR1'
         mr.decode()
-        self.assertEqual(mr.PatientName, 'CompressedSamples^MR1',
-                         "Wrong patient name")
-        self.assertEqual(mr.PatientName, mr[0x10, 0x10].value,
-                         "Name does not match value found when "
-                         "accessed by tag number")
-        got = mr.PixelSpacing
+        assert 'CompressedSamples^MR1' == mr.PatientName
+        assert mr[0x10, 0x10].value == mr.PatientName
+
         DS = pydicom.valuerep.DS
-        expected = [DS('0.3125'), DS('0.3125')]
-        self.assertTrue(got == expected, "Wrong pixel spacing")
+        assert [DS('0.3125'), DS('0.3125')] == mr.PixelSpacing
 
-    def testDeflate(self):
+    def test_deflate(self):
         """Returns correct values for sample data elements in test compressed
          (zlib deflate) file
          """
         # Everything after group 2 is compressed.
         # If we can read anything else, the decompression must have been ok.
         ds = dcmread(deflate_name)
-        got = ds.ConversionType
-        expected = "WSD"
-        self.assertEqual(got, expected,
-                         "Attempted to read deflated file data element "
-                         "Conversion Type, expected '%s', got '%s'" % (
-                             expected, got))
-
-    def testNoPixelsRead(self):
+        assert "WSD" == ds.ConversionType
+
+    def test_no_pixels_read(self):
         """Returns all data elements before pixels using
         stop_before_pixels=False.
         """
@@ -289,13 +249,10 @@ class ReaderTests(unittest.TestCase):
         ctpartial_tags = sorted(ctpartial.keys())
         ctfull = dcmread(ct_name)
         ctfull_tags = sorted(ctfull.keys())
-        msg = ("Tag list of partial CT read (except pixel tag and padding) "
-               "did not match full read")
-        msg += "\nExpected: %r\nGot %r" % (ctfull_tags[:-2], ctpartial_tags)
         missing = [Tag(0x7fe0, 0x10), Tag(0xfffc, 0xfffc)]
-        self.assertEqual(ctfull_tags, ctpartial_tags + missing, msg)
+        assert ctfull_tags == ctpartial_tags + missing
 
-    def testSpecificTags(self):
+    def test_specific_tags(self):
         """Returns only tags specified by user."""
         ctspecific = dcmread(ct_name, specific_tags=[
             Tag(0x0010, 0x0010), 'PatientID', 'ImageType', 'ViewName'])
@@ -306,36 +263,34 @@ class ReaderTests(unittest.TestCase):
             Tag(0x0008, 0x0005), Tag(0x0008, 0x0008),
             Tag(0x0010, 0x0010), Tag(0x0010, 0x0020)
         ]
-        self.assertEqual(expected, ctspecific_tags)
+        assert expected == ctspecific_tags
 
-    def testSpecificTagsWithUnknownLengthSQ(self):
+    def test_specific_tags_with_unknown_length_SQ(self):
         """Returns only tags specified by user."""
         unknown_len_sq_tag = Tag(0x3f03, 0x1001)
-        tags = dcmread(priv_SQ_name, specific_tags=[
-            unknown_len_sq_tag])
+        tags = dcmread(priv_SQ_name, specific_tags=[unknown_len_sq_tag])
         tags = sorted(tags.keys())
-        self.assertEqual([unknown_len_sq_tag], tags)
+        assert [unknown_len_sq_tag] == tags
 
-        tags = dcmread(priv_SQ_name, specific_tags=[
-            'PatientName'])
+        tags = dcmread(priv_SQ_name, specific_tags=['PatientName'])
         tags = sorted(tags.keys())
-        self.assertEqual([], tags)
+        assert [] == tags
 
-    def testSpecificTagsWithUnknownLengthTag(self):
+    def test_specific_tags_with_unknown_length_tag(self):
         """Returns only tags specified by user."""
         unknown_len_tag = Tag(0x7fe0, 0x0010)  # Pixel Data
-        tags = dcmread(emri_jpeg_2k_lossless, specific_tags=[
-            unknown_len_tag])
+        tags = dcmread(emri_jpeg_2k_lossless, specific_tags=[unknown_len_tag])
         tags = sorted(tags.keys())
         # SpecificCharacterSet is always added
-        self.assertEqual([Tag(0x08, 0x05), unknown_len_tag], tags)
+        assert [Tag(0x08, 0x05), unknown_len_tag] == tags
 
-        tags = dcmread(emri_jpeg_2k_lossless, specific_tags=[
-            'SpecificCharacterSet'])
+        tags = dcmread(
+            emri_jpeg_2k_lossless, specific_tags=['SpecificCharacterSet']
+        )
         tags = sorted(tags.keys())
-        self.assertEqual([Tag(0x08, 0x05)], tags)
+        assert [Tag(0x08, 0x05)] == tags
 
-    def testPrivateSQ(self):
+    def test_private_SQ(self):
         """Can read private undefined length SQ without error."""
         # From issues 91, 97, 98. Bug introduced by fast reading, due to
         #    VR=None in raw data elements, then an undefined length private
@@ -345,7 +300,7 @@ class ReaderTests(unittest.TestCase):
         # Simply read the file, in 0.9.5 this generated an exception
         dcmread(priv_SQ_name)
 
-    def testNestedPrivateSQ(self):
+    def test_nested_private_SQ(self):
         """Can successfully read a private SQ which contains additional SQs."""
         # From issue 113. When a private SQ of undefined length is used, the
         #   sequence is read in and the length of the SQ is determined upon
@@ -357,90 +312,63 @@ class ReaderTests(unittest.TestCase):
 
         # Make sure that the entire dataset was read in
         pixel_data_tag = TupleTag((0x7fe0, 0x10))
-        self.assertTrue(pixel_data_tag in ds,
-                        "Entire dataset was not parsed properly. "
-                        "PixelData is not present")
+        assert pixel_data_tag in ds
 
         # Check that the DataElement is indeed a Sequence
         tag = TupleTag((0x01, 0x01))
         seq0 = ds[tag]
-        self.assertEqual(seq0.VR, 'SQ',
-                         "First level sequence not parsed properly")
+        assert 'SQ' == seq0.VR
 
         # Now verify the presence of the nested private SQ
         seq1 = seq0[0][tag]
-        self.assertEqual(seq1.VR, 'SQ',
-                         "Second level sequence not parsed properly")
+        assert 'SQ' == seq1.VR
 
         # Now make sure the values that are parsed are correct
-        got = seq1[0][tag].value
-        expected = b'Double Nested SQ'
-        self.assertEqual(got, expected,
-                         "Expected a value of %s, got %s'" % (expected, got))
+        assert b'Double Nested SQ' == seq1[0][tag].value
+        assert b'Nested SQ' == seq0[0][0x01, 0x02].value
 
-        got = seq0[0][0x01, 0x02].value
-        expected = b'Nested SQ'
-        self.assertEqual(got, expected,
-                         "Expected a value of %s, got %s'" % (expected, got))
-
-    def testNoMetaGroupLength(self):
+    def test_no_meta_group_length(self):
         """Read file with no group length in file meta."""
         # Issue 108 -- iView example file with no group length (0002,0002)
         # Originally crashed, now check no exception, but also check one item
         #     in file_meta, and second one in followinsg dataset
         ds = dcmread(no_meta_group_length)
-        got = ds.InstanceCreationDate
-        expected = "20111130"
-        self.assertEqual(got, expected,
-                         "Sample data element after file meta with no "
-                         "group length failed, expected '%s', got '%s'" % (
-                             expected, got))
-
-    def testNoTransferSyntaxInMeta(self):
+        assert "20111130" == ds.InstanceCreationDate
+
+    def test_no_transfer_syntax_in_meta(self):
         """Read file with file_meta, but has no TransferSyntaxUID in it."""
         # From issue 258: if file has file_meta but no TransferSyntaxUID in it,
         #   should assume default transfer syntax
-        ds = dcmread(
-            meta_missing_tsyntax_name)  # is dicom default transfer syntax
+        ds = dcmread(meta_missing_tsyntax_name)  # is default transfer syntax
 
         # Repeat one test from nested private sequence test to maker sure
         #    file was read correctly
         pixel_data_tag = TupleTag((0x7fe0, 0x10))
-        self.assertTrue(pixel_data_tag in ds,
-                        "Failed to properly read a file with no "
-                        "Transfer Syntax in file_meta")
+        assert pixel_data_tag in ds
 
-    def testExplicitVRLittleEndianNoMeta(self):
+    def test_explicit_VR_little_endian_no_meta(self):
         """Read file without file meta with Little Endian Explicit VR dataset.
         """
         # Example file from CMS XiO 5.0 and above
         # Still need to force read data since there is no 'DICM' marker present
         ds = dcmread(explicit_vr_le_no_meta, force=True)
-        got = ds.InstanceCreationDate
-        expected = "20150529"
-        self.assertEqual(got, expected,
-                         "Sample data element from dataset failed, "
-                         "expected '%s', got '%s'" % (expected, got))
+        assert "20150529" == ds.InstanceCreationDate
 
-    def testExplicitVRBigEndianNoMeta(self):
+    def test_explicit_VR_big_endian_no_meta(self):
         """Read file without file meta with Big Endian Explicit VR dataset."""
         # Example file from CMS XiO 5.0 and above
         # Still need to force read data since there is no 'DICM' marker present
         ds = dcmread(explicit_vr_be_no_meta, force=True)
-        got = ds.InstanceCreationDate
-        expected = "20150529"
-        self.assertEqual(got, expected,
-                         "Sample data element from dataset failed, "
-                         "expected '%s', got '%s'" % (expected, got))
+        assert "20150529" == ds.InstanceCreationDate
 
-    def testPlanarConfig(self):
+    def test_planar_config(self):
         px_data_ds = dcmread(color_px_name)
         pl_data_ds = dcmread(color_pl_name)
         assert px_data_ds.PlanarConfiguration != pl_data_ds.PlanarConfiguration
         if have_numpy:
             px_data = px_data_ds.pixel_array
             pl_data = pl_data_ds.pixel_array
-            self.assertTrue(numpy.all(px_data == pl_data))
+            assert numpy.all(px_data == pl_data)
 
     def test_correct_ambiguous_vr(self):
         """Test correcting ambiguous VR elements read from file"""
@@ -456,8 +384,8 @@ class ReaderTests(unittest.TestCase):
         file_ds.save_as(fp, write_like_original=True)
 
         ds = dcmread(fp, force=True)
-        self.assertEqual(ds[0x00280108].VR, 'US')
-        self.assertEqual(ds.SmallestPixelValueInSeries, 10)
+        assert 'US' == ds[0x00280108].VR
+        assert 10 == ds.SmallestPixelValueInSeries
 
     def test_correct_ambiguous_explicit_vr(self):
         """Test correcting ambiguous VR elements read from file"""
@@ -473,8 +401,8 @@ class ReaderTests(unittest.TestCase):
         file_ds.save_as(fp, write_like_original=True)
 
         ds = dcmread(fp, force=True)
-        self.assertEqual(ds[0x00280108].VR, 'US')
-        self.assertEqual(ds.SmallestPixelValueInSeries, 10)
+        assert 'US' == ds[0x00280108].VR
+        assert 10 == ds.SmallestPixelValueInSeries
 
     def test_correct_ambiguous_vr_compressed(self):
         """Test correcting compressed Pixel Data read from file"""
@@ -487,7 +415,7 @@ class ReaderTests(unittest.TestCase):
         file_ds.save_as(fp, write_like_original=True)
 
         ds = dcmread(fp, force=True)
-        self.assertEqual(ds[0x7fe00010].VR, 'OB')
+        assert 'OB' == ds[0x7fe00010].VR
 
     def test_long_specific_char_set(self):
         """Test that specific character set is read even if it is longer
@@ -502,7 +430,7 @@ class ReaderTests(unittest.TestCase):
         file_ds.save_as(fp, write_like_original=True)
 
         ds = dcmread(fp, defer_size=65, force=True)
-        self.assertEqual(ds[0x00080005].value, long_specific_char_set_value)
+        assert long_specific_char_set_value == ds[0x00080005].value
 
     def test_no_preamble_file_meta_dataset(self):
         """Test correct read of group 2 elements with no preamble."""
@@ -516,11 +444,10 @@ class ReaderTests(unittest.TestCase):
 
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue('MediaStorageSOPClassUID' in ds.file_meta)
-        self.assertEqual(ds.file_meta.TransferSyntaxUID,
-                         ImplicitVRLittleEndian)
-        self.assertEqual(ds.Polarity, 'NORMAL')
-        self.assertEqual(ds.ImageBoxPosition, 1)
+        assert 'MediaStorageSOPClassUID' in ds.file_meta
+        assert ImplicitVRLittleEndian == ds.file_meta.TransferSyntaxUID
+        assert 'NORMAL' == ds.Polarity
+        assert 1 == ds.ImageBoxPosition
 
     def test_no_preamble_command_group_dataset(self):
         """Test correct read of group 0 and 2 elements with no preamble."""
@@ -535,12 +462,11 @@ class ReaderTests(unittest.TestCase):
 
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue('MediaStorageSOPClassUID' in ds.file_meta)
-        self.assertEqual(ds.file_meta.TransferSyntaxUID,
-                         ImplicitVRLittleEndian)
-        self.assertEqual(ds.Polarity, 'NORMAL')
-        self.assertEqual(ds.ImageBoxPosition, 1)
-        self.assertEqual(ds.MessageID, 3)
+        assert 'MediaStorageSOPClassUID' in ds.file_meta
+        assert ImplicitVRLittleEndian == ds.file_meta.TransferSyntaxUID
+        assert 'NORMAL' == ds.Polarity
+        assert 1 == ds.ImageBoxPosition
+        assert 3 == ds.MessageID
 
     def test_group_length_wrong(self):
         """Test file is read correctly even if FileMetaInformationGroupLength
@@ -556,14 +482,13 @@ class ReaderTests(unittest.TestCase):
                       b'\x20\x00\x06\x00\x00\x00\x4e\x4f\x52\x4d\x41\x4c')
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertFalse(len(
-            bytestream) - 12 == ds.file_meta.FileMetaInformationGroupLength)
-        self.assertTrue(ds.file_meta.FileMetaInformationGroupLength == 10)
-        self.assertTrue('MediaStorageSOPClassUID' in ds.file_meta)
-        self.assertEqual(ds.file_meta.TransferSyntaxUID,
-                         ImplicitVRLittleEndian)
-        self.assertEqual(ds.Polarity, 'NORMAL')
-        self.assertEqual(ds.ImageBoxPosition, 1)
+        value = ds.file_meta.FileMetaInformationGroupLength
+        assert not len(bytestream) - 12 == value
+        assert 10 == ds.file_meta.FileMetaInformationGroupLength
+        assert 'MediaStorageSOPClassUID' in ds.file_meta
+        assert ImplicitVRLittleEndian == ds.file_meta.TransferSyntaxUID
+        assert 'NORMAL' == ds.Polarity
+        assert 1 == ds.ImageBoxPosition
 
     def test_preamble_command_meta_no_dataset(self):
         """Test reading only preamble, command and meta elements"""
@@ -586,8 +511,8 @@ class ReaderTests(unittest.TestCase):
         bytestream = preamble + prefix + meta + command
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue('TransferSyntaxUID' in ds.file_meta)
-        self.assertTrue('MessageID' in ds)
+        assert 'TransferSyntaxUID' in ds.file_meta
+        assert 'MessageID' in ds
 
     def test_preamble_meta_no_dataset(self):
         """Test reading only preamble and meta elements"""
@@ -603,9 +528,9 @@ class ReaderTests(unittest.TestCase):
         bytestream = preamble + prefix + meta
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertEqual(ds.preamble, b'\x00' * 128)
-        self.assertTrue('TransferSyntaxUID' in ds.file_meta)
-        self.assertEqual(ds[:], Dataset())
+        assert b'\x00' * 128 == ds.preamble
+        assert 'TransferSyntaxUID' in ds.file_meta
+        assert Dataset() == ds[:]
 
     def test_preamble_commandset_no_dataset(self):
         """Test reading only preamble and command set"""
@@ -622,8 +547,8 @@ class ReaderTests(unittest.TestCase):
 
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue('MessageID' in ds)
-        self.assertEqual(ds.file_meta, Dataset())
+        assert 'MessageID' in ds
+        assert Dataset() == ds.file_meta
 
     def test_meta_no_dataset(self):
         """Test reading only meta elements"""
@@ -635,8 +560,8 @@ class ReaderTests(unittest.TestCase):
                       b'\x30\x30\x38\x2e\x31\x2e\x32\x00')
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue('TransferSyntaxUID' in ds.file_meta)
-        self.assertEqual(ds[:], Dataset())
+        assert 'TransferSyntaxUID' in ds.file_meta
+        assert Dataset() == ds[:]
 
     def test_commandset_no_dataset(self):
         """Test reading only command set elements"""
@@ -649,9 +574,9 @@ class ReaderTests(unittest.TestCase):
                       b'\x00\x00\x08\x02\x00\x00\x00\x01\x01')
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue('MessageID' in ds)
-        self.assertTrue(ds.preamble is None)
-        self.assertEqual(ds.file_meta, Dataset())
+        assert 'MessageID' in ds
+        assert ds.preamble is None
+        assert Dataset() == ds.file_meta
 
     def test_file_meta_dataset_implicit_vr(self):
         """Test reading a file meta dataset that is implicit VR"""
@@ -670,17 +595,17 @@ class ReaderTests(unittest.TestCase):
         bytestream = b''
         fp = BytesIO(bytestream)
         ds = dcmread(fp, force=True)
-        self.assertTrue(ds.preamble is None)
-        self.assertEqual(ds.file_meta, Dataset())
-        self.assertEqual(ds[:], Dataset())
+        assert ds.preamble is None
+        assert Dataset() == ds.file_meta
+        assert Dataset() == ds[:]
 
     def test_empty_file(self):
         """Test reading no elements from file produces empty Dataset"""
         with tempfile.NamedTemporaryFile() as f:
             ds = dcmread(f, force=True)
-            self.assertTrue(ds.preamble is None)
-            self.assertEqual(ds.file_meta, Dataset())
-            self.assertEqual(ds[:], Dataset())
+            assert ds.preamble is None
+            assert Dataset() == ds.file_meta
+            assert Dataset() == ds[:]
 
     def test_dcmread_does_not_raise(self):
         """Test that reading from DicomBytesIO does not raise on EOF.
@@ -722,8 +647,8 @@ class TestIncorrectVR(object):
             ds = read_dataset(
                 self.ds_explicit, is_implicit_VR=True, is_little_endian=True
             )
-        assert ds.SpecificCharacterSet == 'ISO_IR 100'
-        assert ds.StudyDate == '20000101'
+        assert 'ISO_IR 100' == ds.SpecificCharacterSet
+        assert '20000101' == ds.StudyDate
 
     def test_implicit_vr_expected_explicit_used_strict(self):
         config.enforce_valid_values = True
@@ -732,7 +657,8 @@ class TestIncorrectVR(object):
 
         with pytest.raises(InvalidDicomError, match=msg):
             read_dataset(
-                self.ds_explicit, is_implicit_VR=True, is_little_endian=True)
+                self.ds_explicit, is_implicit_VR=True, is_little_endian=True
+            )
 
     def test_explicit_vr_expected_implicit_used(self):
         msg = ('Expected explicit VR, but found implicit VR - '
@@ -742,8 +668,8 @@ class TestIncorrectVR(object):
             ds = read_dataset(
                 self.ds_implicit, is_implicit_VR=False, is_little_endian=True
             )
-        assert ds.SpecificCharacterSet == 'ISO_IR 100'
-        assert ds.StudyDate == '20000101'
+        assert 'ISO_IR 100' == ds.SpecificCharacterSet
+        assert '20000101' == ds.StudyDate
 
     def test_explicit_vr_expected_implicit_used_strict(self):
         config.enforce_valid_values = True
@@ -819,8 +745,8 @@ class TestUnknownVR(object):
             print(ds)
 
 
-class ReadDataElementTests(unittest.TestCase):
-    def setUp(self):
+class TestReadDataElement(object):
+    def setup(self):
         ds = Dataset()
         ds.DoubleFloatPixelData = (b'\x00\x01\x02\x03\x04\x05\x06\x07'
                                    b'\x01\x01\x02\x03\x04\x05\x06\x07')  # OD
@@ -852,7 +778,7 @@ class ReadDataElementTests(unittest.TestCase):
         elem = DataElement(0x7fe00009, 'OD',
                            b'\x00\x01\x02\x03\x04\x05\x06\x07'
                            b'\x01\x01\x02\x03\x04\x05\x06\x07')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_OD_explicit_little(self):
         """Check creation of OD DataElement from byte data works correctly."""
@@ -861,7 +787,7 @@ class ReadDataElementTests(unittest.TestCase):
         elem = DataElement(0x7fe00009, 'OD',
                            b'\x00\x01\x02\x03\x04\x05\x06\x07'
                            b'\x01\x01\x02\x03\x04\x05\x06\x07')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_OL_implicit_little(self):
         """Check creation of OL DataElement from byte data works correctly."""
@@ -870,7 +796,7 @@ class ReadDataElementTests(unittest.TestCase):
         elem = DataElement(0x00720075, 'OL',
                            b'\x00\x01\x02\x03\x04\x05\x06\x07'
                            b'\x01\x01\x02\x03')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_OL_explicit_little(self):
         """Check creation of OL DataElement from byte data works correctly."""
@@ -879,73 +805,76 @@ class ReadDataElementTests(unittest.TestCase):
         elem = DataElement(0x00720075, 'OL',
                            b'\x00\x01\x02\x03\x04\x05\x06\x07'
                            b'\x01\x01\x02\x03')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_UC_implicit_little(self):
         """Check creation of DataElement from byte data works correctly."""
         ds = dcmread(self.fp, force=True)
         ref_elem = ds.get(0x00189908)
         elem = DataElement(0x00189908, 'UC', ['A', 'B', 'C'])
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
         ds = dcmread(self.fp, force=True)
         ref_elem = ds.get(0x00100212)
         elem = DataElement(0x00100212, 'UC', 'Test')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_UC_explicit_little(self):
         """Check creation of DataElement from byte data works correctly."""
         ds = dcmread(self.fp_ex, force=True)
         ref_elem = ds.get(0x00189908)
         elem = DataElement(0x00189908, 'UC', ['A', 'B', 'C'])
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
         ds = dcmread(self.fp_ex, force=True)
         ref_elem = ds.get(0x00100212)
         elem = DataElement(0x00100212, 'UC', 'Test')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_UR_implicit_little(self):
         """Check creation of DataElement from byte data works correctly."""
         ds = dcmread(self.fp, force=True)
         ref_elem = ds.get(0x00080120)  # URNCodeValue
         elem = DataElement(0x00080120, 'UR', 'http://test.com')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
         # Test trailing spaces ignored
         ref_elem = ds.get(0x00081190)  # RetrieveURL
         elem = DataElement(0x00081190, 'UR', 'ftp://test.com')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_UR_explicit_little(self):
         """Check creation of DataElement from byte data works correctly."""
         ds = dcmread(self.fp_ex, force=True)
         ref_elem = ds.get(0x00080120)  # URNCodeValue
         elem = DataElement(0x00080120, 'UR', 'http://test.com')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
         # Test trailing spaces ignored
         ref_elem = ds.get(0x00081190)  # RetrieveURL
         elem = DataElement(0x00081190, 'UR', 'ftp://test.com')
-        self.assertEqual(ref_elem, elem)
+        assert ref_elem == elem
 
     def test_read_AE(self):
         """Check creation of AE DataElement from byte data works correctly."""
         ds = dcmread(self.fp, force=True)
-        self.assertEqual(ds.DestinationAE, 'TEST  12')
+        assert 'TEST  12' == ds.DestinationAE
 
 
-class DeferredReadTests(unittest.TestCase):
+class TestDeferredRead(object):
     """Test that deferred data element reading (for large size)
     works as expected
     """
-
     # Copy one of test files and use temporarily, then later remove.
-    def setUp(self):
+    def setup(self):
         self.testfile_name = ct_name + ".tmp"
         shutil.copyfile(ct_name, self.testfile_name)
 
-    def testTimeCheck(self):
+    def teardown(self):
+        if os.path.exists(self.testfile_name):
+            os.remove(self.testfile_name)
+
+    def test_time_check(self):
         """Deferred read warns if file has been modified"""
         ds = dcmread(self.testfile_name, defer_size='2 kB')
         from time import sleep
@@ -953,35 +882,27 @@ class DeferredReadTests(unittest.TestCase):
         with open(self.testfile_name, "r+") as f:
             f.write('\0')  # "touch" the file
 
-        def read_value():
+        msg = r"Deferred read warning -- file modification time has changed"
+        with pytest.warns(UserWarning, match=msg):
             ds.PixelData
 
-        with pytest.warns(UserWarning,
-                          match="Deferred read warning -- file modification "
-                                "time has changed"):
-            read_value()
-
-    def testFileExists(self):
-        """Deferred read raises error if file no longer exists....."""
+    def test_file_exists(self):
+        """Deferred read raises error if file no longer exists."""
         ds = dcmread(self.testfile_name, defer_size=2000)
         os.remove(self.testfile_name)
-
-        def read_value():
+        with pytest.raises(IOError):
             ds.PixelData
 
-        self.assertRaises(IOError, read_value)
-
-    def testValuesIdentical(self):
-        """Deferred values exactly matches normal read..............."""
+    def test_values_identical(self):
+        """Deferred values exactly matches normal read."""
         ds_norm = dcmread(self.testfile_name)
         ds_defer = dcmread(self.testfile_name, defer_size=2000)
         for data_elem in ds_norm:
             tag = data_elem.tag
-            self.assertEqual(data_elem.value, ds_defer[tag].value,
-                             "Mismatched value for tag %r" % tag)
+            assert data_elem.value == ds_defer[tag].value
 
-    def testZippedDeferred(self):
-        """Deferred values from a gzipped file works.............."""
+    def test_zipped_deferred(self):
+        """Deferred values from a gzipped file works."""
         # Arose from issue 103 "Error for defer_size read of gzip file object"
         fobj = gzip.open(gzip_name)
         ds = dcmread(fobj, defer_size=1)
@@ -990,48 +911,37 @@ class DeferredReadTests(unittest.TestCase):
         # the right place, it was re-opened as a normal file, not a zip file
         ds.InstanceNumber
 
-    def tearDown(self):
-        if os.path.exists(self.testfile_name):
-            os.remove(self.testfile_name)
 
-
-class ReadTruncatedFileTests(unittest.TestCase):
+class TestReadTruncatedFile(object):
     def testReadFileWithMissingPixelData(self):
         mr = dcmread(truncated_mr_name)
         mr.decode()
-        self.assertEqual(mr.PatientName, 'CompressedSamples^MR1',
-                         "Wrong patient name")
-        self.assertEqual(mr.PatientName, mr[0x10, 0x10].value,
-                         "Name does not match value found when "
-                         "accessed by tag number")
-        got = mr.PixelSpacing
+        assert 'CompressedSamples^MR1' == mr.PatientName
+        assert mr.PatientName == mr[0x10, 0x10].value
         DS = pydicom.valuerep.DS
-        expected = [DS('0.3125'), DS('0.3125')]
-        self.assertTrue(got == expected, "Wrong pixel spacing")
+        assert [DS('0.3125'), DS('0.3125')] == mr.PixelSpacing
 
-    @unittest.skipUnless(
-        have_numpy and not have_gdcm_handler,
-        "Numpy not installed or gdcm is installed, "
-        "gdcm fixes truncated data??")
+    @pytest.mark.skipif(not have_numpy or have_gdcm_handler,
+                        reason="Missing numpy or GDCM present")
     def testReadFileWithMissingPixelDataArray(self):
         mr = dcmread(truncated_mr_name)
         mr.decode()
         # Need to escape brackets
         msg = (
-            r"The length of the pixel data in the dataset doesn't match the "
-            r"expected amount \(8130 vs. 8192 bytes\). The dataset may be "
-            r"corrupted or there may be an issue with the pixel data handler."
+            r"The length of the pixel data in the dataset \(8130 bytes\) "
+            r"doesn't match the expected length \(8192 bytes\). "
+            r"The dataset may be corrupted or there may be an issue with "
+            r"the pixel data handler."
         )
         with pytest.raises(ValueError, match=msg):
             mr.pixel_array
 
 
-class FileLikeTests(unittest.TestCase):
+class TestFileLike(object):
     """Test that can read DICOM files with file-like object rather than
     filename
     """
-
-    def testReadFileGivenFileObject(self):
+    def test_read_file_given_file_object(self):
         """filereader: can read using already opened file............"""
         f = open(ct_name, 'rb')
         ct = dcmread(f)
@@ -1040,31 +950,26 @@ class FileLikeTests(unittest.TestCase):
         got = ct.ImagePositionPatient
         DS = pydicom.valuerep.DS
         expected = [DS('-158.135803'), DS('-179.035797'), DS('-75.699997')]
-        self.assertTrue(got == expected,
-                        "ImagePosition(Patient) values not as expected")
-        self.assertEqual(ct.file_meta.ImplementationClassUID,
-                         '1.3.6.1.4.1.5962.2',
-                         "ImplementationClassUID not the expected value")
-        self.assertEqual(ct.file_meta.ImplementationClassUID,
-                         ct.file_meta[0x2, 0x12].value,
-                         "ImplementationClassUID does not match the "
-                         "value accessed by tag number")
+        assert expected == got
+        assert '1.3.6.1.4.1.5962.2' == ct.file_meta.ImplementationClassUID
+        value = ct.file_meta[0x2, 0x12].value
+        assert ct.file_meta.ImplementationClassUID == value
+
         # (0020, 0032) Image Position (Patient)
         # [-158.13580300000001, -179.035797, -75.699996999999996]
         got = ct.ImagePositionPatient
         expected = [DS('-158.135803'), DS('-179.035797'), DS('-75.699997')]
-        self.assertTrue(got == expected,
-                        "ImagePosition(Patient) values not as expected")
-        self.assertEqual(ct.Rows, 128, "Rows not 128")
-        self.assertEqual(ct.Columns, 128, "Columns not 128")
-        self.assertEqual(ct.BitsStored, 16, "Bits Stored not 16")
-        self.assertEqual(len(ct.PixelData), 128 * 128 * 2,
-                         "Pixel data not expected length")
+        assert expected == got
+        assert 128 == ct.Rows
+        assert 128 == ct.Columns
+        assert 16 == ct.BitsStored
+        assert 128 * 128 * 2 == len(ct.PixelData)
+
         # Should also be able to close the file ourselves without
         # exception raised:
         f.close()
 
-    def testReadFileGivenFileLikeObject(self):
+    def test_read_file_given_file_like_object(self):
         """filereader: can read using a file-like (BytesIO) file...."""
         with open(ct_name, 'rb') as f:
             file_like = BytesIO(f.read())
@@ -1073,10 +978,8 @@ class FileLikeTests(unittest.TestCase):
         got = ct.ImagePositionPatient
         DS = pydicom.valuerep.DS
         expected = [DS('-158.135803'), DS('-179.035797'), DS('-75.699997')]
-        self.assertTrue(got == expected,
-                        "ImagePosition(Patient) values not as expected")
-        self.assertEqual(len(ct.PixelData), 128 * 128 * 2,
-                         "Pixel data not expected length")
+        assert expected == got
+        assert 128 * 128 * 2 == len(ct.PixelData)
         # Should also be able to close the file ourselves without
         # exception raised:
         file_like.close()
@@ -1121,10 +1024,3 @@ class TestDataElementGenerator(object):
         gen = data_element_generator(fp, False, False)
         elem = DataElement(0x00100010, 'PN', 'ABCDEF')
         assert elem == DataElement_from_raw(next(gen), 'ISO_IR 100')
-
-
-if __name__ == "__main__":
-    # This is called if run alone, but not if loaded through run_tests.py
-    # If not run from the directory where the sample images are, then need
-    # to switch there
-    unittest.main()
diff --git a/pydicom/tests/test_fixes.py b/pydicom/tests/test_fixes.py
index 775b8da3b..11e5f3f08 100644
--- a/pydicom/tests/test_fixes.py
+++ b/pydicom/tests/test_fixes.py
@@ -1,7 +1,6 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""Test fixes modules"""
+"""Unit tests for pydicom.util.fixes module."""
 
-import unittest
 import copy
 import pickle
 
@@ -16,8 +15,9 @@ import pydicom as pydicom_module
 from pydicom import compat
 from pydicom.util.fixes import timezone
 
-pickle_choices = [(pickle, pickle, proto)
-                  for proto in range(pickle.HIGHEST_PROTOCOL + 1)]
+pickle_choices = [
+    (pickle, pickle, proto) for proto in range(pickle.HIGHEST_PROTOCOL + 1)
+]
 
 ZERO = timedelta(0)
 HOUR = timedelta(hours=1)
@@ -38,7 +38,6 @@ def first_sunday_on_or_after(dt):
 
 
 class USTimeZone(tzinfo):
-
     def __init__(self, hours, reprname, stdname, dstname):
         self.stdoffset = timedelta(hours=hours)
         self.reprname = reprname
@@ -83,9 +82,8 @@ class USTimeZone(tzinfo):
 Eastern = USTimeZone(-5, "Eastern",  "EST", "EDT")
 
 
-@pytest.mark.skipif(not compat.in_py2,
-                    reason='only test the backport to Python 2')
-class TestTimeZone(unittest.TestCase):
+@pytest.mark.skipif(not compat.in_py2, reason='Only test backport in Python 2')
+class TestTimeZone(object):
     """Backport of datetime.timezone tests.
 
     Notes
@@ -95,8 +93,7 @@ class TestTimeZone(unittest.TestCase):
     Foundation (https://docs.python.org/3/license.html)
 
     """
-
-    def setUp(self):
+    def setup(self):
         self.ACDT = timezone(timedelta(hours=9.5), 'ACDT')
         self.EST = timezone(-timedelta(hours=5), 'EST')
         self.DT = datetime(2010, 1, 1)
@@ -104,7 +101,7 @@ class TestTimeZone(unittest.TestCase):
     def test_str(self):
         for tz in [self.ACDT, self.EST, timezone.utc,
                    timezone.min, timezone.max]:
-            self.assertEqual(str(tz), tz.tzname(None))
+            assert tz.tzname(None) == str(tz)
 
     def test_repr(self):
         datetime = datetime_module
@@ -113,133 +110,128 @@ class TestTimeZone(unittest.TestCase):
                    timezone.min, timezone.max]:
             # test round-trip
             tzrep = repr(tz)
-            self.assertEqual(tz, eval(tzrep))
+            assert tz == eval(tzrep)
 
     def test_class_members(self):
         limit = timedelta(hours=23, minutes=59)
-        self.assertEqual(timezone.utc.utcoffset(None), ZERO)
-        self.assertEqual(timezone.min.utcoffset(None), -limit)
-        self.assertEqual(timezone.max.utcoffset(None), limit)
+        assert ZERO == timezone.utc.utcoffset(None)
+        assert -limit == timezone.min.utcoffset(None)
+        assert limit == timezone.max.utcoffset(None)
 
     def test_constructor(self):
-        self.assertIs(timezone.utc, timezone(timedelta(0)))
-        self.assertIsNot(timezone.utc, timezone(timedelta(0), 'UTC'))
-        self.assertEqual(timezone.utc, timezone(timedelta(0), 'UTC'))
+        assert timezone.utc is timezone(timedelta(0))
+        assert timezone.utc is not timezone(timedelta(0), 'UTC')
+        assert timezone(timedelta(0), 'UTC') == timezone.utc
         # invalid offsets
         for invalid in [timedelta(microseconds=1), timedelta(1, 1),
                         timedelta(seconds=1), timedelta(1), -timedelta(1)]:
-            self.assertRaises(ValueError, timezone, invalid)
-            self.assertRaises(ValueError, timezone, -invalid)
+            with pytest.raises(ValueError):
+                timezone(invalid)
+            with pytest.raises(ValueError):
+                timezone(-invalid)
 
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             timezone(None)
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             timezone(42)
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             timezone(ZERO, None)
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             timezone(ZERO, 42)
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             timezone(ZERO, 'ABC', 'extra')
 
     def test_inheritance(self):
-        self.assertIsInstance(timezone.utc, tzinfo)
-        self.assertIsInstance(self.EST, tzinfo)
+        assert isinstance(timezone.utc, tzinfo)
+        assert isinstance(self.EST, tzinfo)
 
     def test_utcoffset(self):
         dummy = self.DT
         for h in [0, 1.5, 12]:
             offset = h * HOUR.total_seconds()
             offset = timedelta(seconds=offset)
-            self.assertEqual(offset, timezone(offset).utcoffset(dummy))
-            self.assertEqual(-offset, timezone(-offset).utcoffset(dummy))
+            assert offset == timezone(offset).utcoffset(dummy)
+            assert -offset == timezone(-offset).utcoffset(dummy)
 
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             self.EST.utcoffset('')
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             self.EST.utcoffset(5)
 
     def test_dst(self):
-        self.assertIsNone(timezone.utc.dst(self.DT))
+        assert timezone.utc.dst(self.DT) is None
 
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             self.EST.dst('')
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             self.EST.dst(5)
 
     def test_tzname(self):
-        self.assertTrue('UTC' in timezone.utc.tzname(None))
-        self.assertTrue('UTC' in timezone(ZERO).tzname(None))
-        self.assertEqual('UTC-05:00', timezone(timedelta(
-            hours=-5)).tzname(None))
-        self.assertEqual('UTC+09:30', timezone(timedelta(
-            hours=9.5)).tzname(None))
-        self.assertEqual('UTC-00:01',
-                         timezone(timedelta(minutes=-1)).tzname(None))
-        self.assertEqual('XYZ', timezone(-5 * HOUR, 'XYZ').tzname(None))
-
-        with self.assertRaises(TypeError):
+        assert 'UTC' in timezone.utc.tzname(None)
+        assert 'UTC' in timezone(ZERO).tzname(None)
+        assert 'UTC-05:00' == timezone(timedelta(hours=-5)).tzname(None)
+        assert 'UTC+09:30' == timezone(timedelta(hours=9.5)).tzname(None)
+        assert 'UTC-00:01' == timezone(timedelta(minutes=-1)).tzname(None)
+        assert 'XYZ' == timezone(-5 * HOUR, 'XYZ').tzname(None)
+
+        with pytest.raises(TypeError):
             self.EST.tzname('')
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             self.EST.tzname(5)
 
     def test_fromutc(self):
-        with self.assertRaises(ValueError):
+        with pytest.raises(ValueError):
             timezone.utc.fromutc(self.DT)
-        with self.assertRaises(TypeError):
+        with pytest.raises(TypeError):
             timezone.utc.fromutc('not datetime')
         for tz in [self.EST, self.ACDT, Eastern]:
             utctime = self.DT.replace(tzinfo=tz)
             local = tz.fromutc(utctime)
-            self.assertEqual(local - utctime, tz.utcoffset(local))
-            self.assertEqual(local,
-                             self.DT.replace(tzinfo=timezone.utc))
+            assert local - utctime == tz.utcoffset(local)
+            assert local == self.DT.replace(tzinfo=timezone.utc)
 
     def test_comparison(self):
-        self.assertNotEqual(timezone(ZERO), timezone(HOUR))
-        self.assertEqual(timezone(HOUR), timezone(HOUR))
-        self.assertEqual(timezone(-5 * HOUR), timezone(-5 * HOUR, 'EST'))
-        with self.assertRaises(TypeError):
+        assert timezone(ZERO) != timezone(HOUR)
+        assert timezone(HOUR) == timezone(HOUR)
+        assert timezone(-5 * HOUR) == timezone(-5 * HOUR, 'EST')
+        with pytest.raises(TypeError):
             timezone(ZERO) < timezone(ZERO)
-        self.assertIn(timezone(ZERO), {timezone(ZERO)})
-        self.assertTrue(timezone(ZERO) is not None)
-        self.assertFalse(timezone(ZERO) is None)
-        self.assertNotEqual(timezone(ZERO), 'random')
+        assert timezone(ZERO) in {timezone(ZERO)}
+        assert timezone(ZERO) is not None
+        assert not timezone(ZERO) is None
+        assert 'random' != timezone(ZERO)
 
     def test_aware_datetime(self):
         # test that timezone instances can be used by datetime
         t = datetime(1, 1, 1)
         for tz in [timezone.min, timezone.max, timezone.utc]:
             print(tz.tzname(t))
-            self.assertEqual(tz.tzname(t),
-                             t.replace(tzinfo=tz).tzname())
-            self.assertEqual(tz.utcoffset(t),
-                             t.replace(tzinfo=tz).utcoffset())
-            self.assertEqual(tz.dst(t),
-                             t.replace(tzinfo=tz).dst())
+            assert t.replace(tzinfo=tz).tzname() == tz.tzname(t)
+            assert t.replace(tzinfo=tz).utcoffset() == tz.utcoffset(t)
+            assert t.replace(tzinfo=tz).dst() == tz.dst(t)
 
     def test_pickle(self):
         for tz in self.ACDT, self.EST, timezone.min, timezone.max:
             for pickler, unpickler, proto in pickle_choices:
                 tz_copy = unpickler.loads(pickler.dumps(tz, proto))
-                self.assertEqual(tz_copy, tz)
+                assert tz == tz_copy
         tz = timezone.utc
         for pickler, unpickler, proto in pickle_choices:
             tz_copy = unpickler.loads(pickler.dumps(tz, proto))
-            self.assertIs(tz_copy, tz)
+            assert tz_copy is tz
 
     def test_copy(self):
         for tz in self.ACDT, self.EST, timezone.min, timezone.max:
             tz_copy = copy.copy(tz)
-            self.assertEqual(tz_copy, tz)
+            assert tz == tz_copy
         tz = timezone.utc
         tz_copy = copy.copy(tz)
-        self.assertIs(tz_copy, tz)
+        assert tz_copy is tz
 
     def test_deepcopy(self):
         for tz in self.ACDT, self.EST, timezone.min, timezone.max:
             tz_copy = copy.deepcopy(tz)
-            self.assertEqual(tz_copy, tz)
+            assert tz == tz_copy
         tz = timezone.utc
         tz_copy = copy.deepcopy(tz)
-        self.assertIs(tz_copy, tz)
+        assert tz_copy is tz
diff --git a/pydicom/tests/test_gdcm_pixel_data.py b/pydicom/tests/test_gdcm_pixel_data.py
index 5a4b9d9e5..36afc2496 100644
--- a/pydicom/tests/test_gdcm_pixel_data.py
+++ b/pydicom/tests/test_gdcm_pixel_data.py
@@ -1,23 +1,27 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
 # -*- coding: utf-8 -*-
+"""Unit tests for the GDCM Pixel Data handler."""
 
-import unittest
 import os
 import sys
 import tempfile
 import shutil
+
 import pytest
+
 import pydicom
 from pydicom.filereader import dcmread
 from pydicom.data import get_testdata_files
 from pydicom.pixel_data_handlers.util import _convert_YBR_FULL_to_RGB
 from pydicom.tag import Tag
 from pydicom import compat
+
 gdcm_missing_message = "GDCM is not available in this test environment"
 gdcm_im_missing_message = "GDCM is not available or in-memory decoding"\
     " not supported with this GDCM version"
 gdcm_present_message = "GDCM is being tested"
 have_numpy_testing = True
+
 try:
     import numpy.testing
 except ImportError as e:
@@ -30,23 +34,14 @@ try:
 except AttributeError:
     have_pytest_param = False
 
-try:
-    import pydicom.pixel_data_handlers.gdcm_handler as gdcm_handler
-    HAVE_GDCM = gdcm_handler.HAVE_GDCM
-    HAVE_GDCM_IN_MEMORY_SUPPORT = gdcm_handler.HAVE_GDCM_IN_MEMORY_SUPPORT
-    if HAVE_GDCM:
-        import gdcm
-except ImportError as e:
-    HAVE_GDCM = False
-    HAVE_GDCM_IN_MEMORY_SUPPORT = False
-    gdcm_handler = None
+from pydicom.pixel_data_handlers import numpy_handler
+have_numpy_handler = numpy_handler.is_available()
 
-try:
-    import pydicom.pixel_data_handlers.numpy_handler as numpy_handler
-    HAVE_NP = numpy_handler.HAVE_NP
-except ImportError:
-    HAVE_NP = False
-    numpy_handler = None
+from pydicom.pixel_data_handlers import gdcm_handler
+HAVE_GDCM = gdcm_handler.is_available()
+HAVE_GDCM_IN_MEMORY_SUPPORT = gdcm_handler.HAVE_GDCM_IN_MEMORY_SUPPORT
+if HAVE_GDCM:
+    import gdcm
 
 
 empty_number_tags_name = get_testdata_files(
@@ -110,8 +105,8 @@ dir_name = os.path.dirname(sys.argv[0])
 save_dir = os.getcwd()
 
 
-class GDCM_JPEG_LS_Tests_no_gdcm(unittest.TestCase):
-    def setUp(self):
+class TestGDCM_JPEG_LS_no_gdcm(object):
+    def setup(self):
         if compat.in_py2:
             self.utf8_filename = os.path.join(
                 tempfile.gettempdir(), "ДИКОМ.dcm")
@@ -129,21 +124,21 @@ class GDCM_JPEG_LS_Tests_no_gdcm(unittest.TestCase):
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = []
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
         os.remove(self.unicode_filename)
 
     def test_JPEG_LS_PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_ls_lossless.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_ls_lossless.pixel_array
 
     def test_emri_JPEG_LS_PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_ls_lossless.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_ls_lossless.pixel_array
 
 
-class GDCM_JPEG2000Tests_no_gdcm(unittest.TestCase):
-    def setUp(self):
+class TestGDCM_JPEG2000_no_gdcm(object):
+    def setup(self):
         self.jpeg_2k = dcmread(jpeg2000_name)
         self.jpeg_2k_lossless = dcmread(jpeg2000_lossless_name)
         self.mr_small = dcmread(mr_name)
@@ -153,7 +148,7 @@ class GDCM_JPEG2000Tests_no_gdcm(unittest.TestCase):
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = []
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def test_JPEG2000(self):
@@ -161,70 +156,57 @@ class GDCM_JPEG2000Tests_no_gdcm(unittest.TestCase):
         # XX also tests multiple-valued AT data element
         expected = [Tag(0x0054, 0x0010), Tag(0x0054, 0x0020)]
         got = self.jpeg_2k.FrameIncrementPointer
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG2000 file, Frame Increment Pointer: "
-            "expected %s, got %s" % (expected, got))
+        assert expected == got
 
         got = self.jpeg_2k.DerivationCodeSequence[0].CodeMeaning
         expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG200 file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert expected == got
 
-    def test_JPEG2000PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_2k_lossless.pixel_array
+    def test_JPEG2000_pixel_array(self):
+        with pytest.raises(NotImplementedError):
+            self.jpeg_2k_lossless.pixel_array
 
-    def test_emri_JPEG2000PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_2k_lossless.pixel_array
+    def test_emri_JPEG2000_pixel_array(self):
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_2k_lossless.pixel_array
 
     def test_jpeg2000_lossy(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.sc_rgb_jpeg2k_gdcm_KY.pixel_array
-
+        with pytest.raises(NotImplementedError):
+            self.sc_rgb_jpeg2k_gdcm_KY.pixel_array
 
-class GDCM_JPEGlossyTests_no_gdcm(unittest.TestCase):
 
-    def setUp(self):
+class TestGDCM_JPEGlossy_no_gdcm(object):
+    def setup(self):
         self.jpeg_lossy = dcmread(jpeg_lossy_name)
         self.color_3d_jpeg = dcmread(color_3d_jpeg_baseline)
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = []
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def test_JPEGlossy(self):
         """JPEG-lossy: Returns correct values for sample data elements"""
         got = self.jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
         expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossy file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert expected == got
 
-    def test_JPEGlossyPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossy.pixel_array
+    def test_JPEGlossy_pixel_array(self):
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossy.pixel_array
 
-    def test_JPEGBaselineColor3DPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.color_3d_jpeg.pixel_array
+    def test_JPEGBaseline_color_3D_pixel_array(self):
+        with pytest.raises(NotImplementedError):
+            self.color_3d_jpeg.pixel_array
 
 
-class GDCM_JPEGlosslessTests_no_gdcm(unittest.TestCase):
-    def setUp(self):
+class TestGDCM_JPEGlossless_no_gdcm(object):
+    def setup(self):
         self.jpeg_lossless = dcmread(jpeg_lossless_name)
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = []
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def testJPEGlossless(self):
@@ -234,16 +216,12 @@ class GDCM_JPEGlosslessTests_no_gdcm(unittest.TestCase):
             SourceImageSequence[0].\
             PurposeOfReferenceCodeSequence[0].CodeMeaning
         expected = 'Uncompressed predecessor'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossless file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert expected == got
 
-    def testJPEGlosslessPixelArray(self):
+    def testJPEGlossless_pixel_array(self):
         """JPEGlossless: Fails gracefully when uncompressed data asked for"""
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossless.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossless.pixel_array
 
 
 if have_pytest_param:
@@ -404,7 +382,7 @@ else:
         with_gdcm_params = []
 
 
-class TestsWithGDCM():
+class TestsWithGDCM(object):
     @pytest.fixture(params=with_gdcm_params, scope='class', autouse=True)
     def with_gdcm(self, request):
         original_value = HAVE_GDCM_IN_MEMORY_SUPPORT
@@ -485,18 +463,14 @@ class TestsWithGDCM():
     def test_JPEG_LS_PixelArray(self, jpeg_ls_lossless, mr_small):
         a = jpeg_ls_lossless.pixel_array
         b = mr_small.pixel_array
-        assert a.mean() == b.mean(), "using GDCM Decoded pixel data is not "\
-            "all {0} (mean == {1})".format(b.mean(), a.mean())
-
+        assert a.mean() == b.mean()
         assert a.flags.writeable
 
     def test_emri_JPEG_LS_PixelArray_with_gdcm(self, emri_jpeg_ls_lossless,
                                                emri_small):
         a = emri_jpeg_ls_lossless.pixel_array
         b = emri_small.pixel_array
-        assert a.mean() == b.mean(), "Decoded pixel data is not all {0} "\
-            "(mean == {1})".format(b.mean(), a.mean())
-
+        assert a.mean() == b.mean()
         assert a.flags.writeable
 
     def test_JPEG2000(self, jpeg_2k):
@@ -504,28 +478,21 @@ class TestsWithGDCM():
         # XX also tests multiple-valued AT data element
         expected = [Tag(0x0054, 0x0010), Tag(0x0054, 0x0020)]
         got = jpeg_2k.FrameIncrementPointer
-        assert got == expected, "JPEG2000 file, Frame Increment Pointer: "\
-            "expected %s, got %s" % (expected, got)
+        assert expected == got
 
         got = jpeg_2k.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        assert got == expected, "JPEG200 file, Code Meaning got %s, "\
-            "expected %s" % (got, expected)
+        assert 'Lossy Compression' == got
 
     def test_JPEG2000PixelArray(self, jpeg_2k_lossless, mr_small):
         a = jpeg_2k_lossless.pixel_array
         b = mr_small.pixel_array
-        assert a.mean() == b.mean(), "Decoded pixel data is not all {0} "\
-            "(mean == {1})".format(b.mean(), a.mean())
-
+        assert a.mean() == b.mean()
         assert a.flags.writeable
 
     def test_emri_JPEG2000PixelArray(self, emri_jpeg_2k_lossless, emri_small):
         a = emri_jpeg_2k_lossless.pixel_array
         b = emri_small.pixel_array
-        assert a.mean() == b.mean(), "Decoded pixel data is not all {0} "\
-            "(mean == {1})".format(b.mean(), a.mean())
-
+        assert a.mean() == b.mean()
         assert a.flags.writeable
 
     def test_JPEG2000_lossy(self, sc_rgb_jpeg2k_gdcm_KY,
@@ -535,8 +502,7 @@ class TestsWithGDCM():
         if have_numpy_testing:
             numpy.testing.assert_array_equal(a, b)
         else:
-            assert a.mean() == b.mean(), "Decoded pixel data is not all {0} "\
-                "(mean == {1})".format(b.mean(), a.mean())
+            assert a.mean() == b.mean()
 
         assert a.flags.writeable
 
@@ -545,53 +511,46 @@ class TestsWithGDCM():
         got = jpeg_lossless.\
             SourceImageSequence[0].\
             PurposeOfReferenceCodeSequence[0].CodeMeaning
-        expected = 'Uncompressed predecessor'
-        assert got == expected, "JPEG-lossless file, Code Meaning got %s, "\
-            "expected %s" % (got, expected)
+        assert 'Uncompressed predecessor' == got
 
     def test_JPEGlosslessPixelArray(self, jpeg_lossless):
         """JPEGlossless: Fails gracefully when uncompressed data asked for"""
         a = jpeg_lossless.pixel_array
-        assert a.shape, (1024, 256)
+        assert (1024, 256) == a.shape
         # this test points were manually identified in Osirix viewer
-        assert a[420, 140], 227
-        assert a[230, 120], 105
-
+        assert 227 == a[420, 140]
+        assert 105 == a[230, 120]
         assert a.flags.writeable
 
     def test_JPEGlossless_odd_data_size(self, jpeg_lossless_odd_data_size):
         pixel_data = jpeg_lossless_odd_data_size.pixel_array
-        assert pixel_data.nbytes == 27
-        assert pixel_data.shape == (3, 3, 3)
+        assert 27 == pixel_data.nbytes
+        assert (3, 3, 3) == pixel_data.shape
 
     def test_JPEGlossy(self, jpeg_lossy):
         """JPEG-lossy: Returns correct values for sample data elements"""
         got = jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        assert got == expected, "JPEG-lossy file, Code Meaning got %s, "\
-            "expected %s" % (got, expected)
+        assert 'Lossy Compression' == got
 
     def test_JPEGlossyPixelArray(self, jpeg_lossy):
         a = jpeg_lossy.pixel_array
-        assert a.shape == (1024, 256)
+        assert (1024, 256) == a.shape
         # this test points were manually identified in Osirix viewer
-        assert a[420, 140] == 244
-        assert a[230, 120] == 95
-
+        assert 244 == a[420, 140]
+        assert 95 == a[230, 120]
         assert a.flags.writeable
 
     def test_JPEGBaselineColor3DPixelArray(self, color_3d_jpeg):
-        assert color_3d_jpeg.PhotometricInterpretation == "YBR_FULL_422"
+        assert "YBR_FULL_422" == color_3d_jpeg.PhotometricInterpretation
         a = color_3d_jpeg.pixel_array
 
         assert a.flags.writeable
-
-        assert a.shape == (120, 480, 640, 3)
+        assert (120, 480, 640, 3) == a.shape
         a = _convert_YBR_FULL_to_RGB(a)
         # this test points were manually identified in Osirix viewer
-        assert tuple(a[3, 159, 290, :]) == (41, 41, 41)
-        assert tuple(a[3, 169, 290, :]) == (57, 57, 57)
-        assert color_3d_jpeg.PhotometricInterpretation == "YBR_FULL_422"
+        assert (41, 41, 41) == tuple(a[3, 159, 290, :])
+        assert (57, 57, 57) == tuple(a[3, 169, 290, :])
+        assert "YBR_FULL_422" == color_3d_jpeg.PhotometricInterpretation
 
     @pytest.mark.parametrize(
         "image,PhotometricInterpretation,results,convert_yuv_to_rgb",
@@ -605,24 +564,24 @@ class TestsWithGDCM():
 
         assert a.flags.writeable
 
-        assert a.shape == (100, 100, 3)
+        assert (100, 100, 3) == a.shape
         if convert_yuv_to_rgb:
             a = _convert_YBR_FULL_to_RGB(a)
         # this test points are from the ImageComments tag
-        assert tuple(a[5, 50, :]) == results[0]
-        assert tuple(a[15, 50, :]) == results[1]
-        assert tuple(a[25, 50, :]) == results[2]
-        assert tuple(a[35, 50, :]) == results[3]
-        assert tuple(a[45, 50, :]) == results[4]
-        assert tuple(a[55, 50, :]) == results[5]
-        assert tuple(a[65, 50, :]) == results[6]
-        assert tuple(a[75, 50, :]) == results[7]
-        assert tuple(a[85, 50, :]) == results[8]
-        assert tuple(a[95, 50, :]) == results[9]
-        assert t.PhotometricInterpretation == PhotometricInterpretation
-
-
-class TestSupportFunctions():
+        assert results[0] == tuple(a[5, 50, :])
+        assert results[1] == tuple(a[15, 50, :])
+        assert results[2] == tuple(a[25, 50, :])
+        assert results[3] == tuple(a[35, 50, :])
+        assert results[4] == tuple(a[45, 50, :])
+        assert results[5] == tuple(a[55, 50, :])
+        assert results[6] == tuple(a[65, 50, :])
+        assert results[7] == tuple(a[75, 50, :])
+        assert results[8] == tuple(a[85, 50, :])
+        assert results[9] == tuple(a[95, 50, :])
+        assert PhotometricInterpretation == t.PhotometricInterpretation
+
+
+class TestSupportFunctions(object):
     @pytest.fixture(scope='class')
     def dataset_2d(self):
         return dcmread(mr_name)
@@ -641,8 +600,8 @@ class TestSupportFunctions():
             self, dataset_2d):
         data_element = gdcm_handler.create_data_element(dataset_2d)
 
-        assert data_element.GetTag().GetGroup() == 0x7fe0
-        assert data_element.GetTag().GetElement() == 0x0010
+        assert 0x7fe0 == data_element.GetTag().GetGroup()
+        assert 0x0010 == data_element.GetTag().GetElement()
         assert data_element.GetSequenceOfFragments() is None
         assert data_element.GetByteValue() is not None
 
@@ -652,8 +611,8 @@ class TestSupportFunctions():
             self, dataset_2d_compressed):
         data_element = gdcm_handler.create_data_element(dataset_2d_compressed)
 
-        assert data_element.GetTag().GetGroup() == 0x7fe0
-        assert data_element.GetTag().GetElement() == 0x0010
+        assert 0x7fe0 == data_element.GetTag().GetGroup()
+        assert 0x0010 == data_element.GetTag().GetElement()
         assert data_element.GetSequenceOfFragments() is not None
         assert data_element.GetByteValue() is None
 
@@ -662,8 +621,8 @@ class TestSupportFunctions():
     def test_create_data_element_from_3d_dataset(self, dataset_3d):
         data_element = gdcm_handler.create_data_element(dataset_3d)
 
-        assert data_element.GetTag().GetGroup() == 0x7fe0
-        assert data_element.GetTag().GetElement() == 0x0010
+        assert 0x7fe0 == data_element.GetTag().GetGroup()
+        assert 0x0010 == data_element.GetTag().GetElement()
         assert data_element.GetSequenceOfFragments() is not None
         assert data_element.GetByteValue() is None
 
@@ -672,44 +631,48 @@ class TestSupportFunctions():
     def test_create_image_from_2d_dataset(self, dataset_2d):
         data_element = gdcm_handler.create_data_element(dataset_2d)
         image = gdcm_handler.create_image(dataset_2d, data_element)
-        assert image.GetNumberOfDimensions() == 2
-        assert image.GetDimensions() == [dataset_2d.Rows, dataset_2d.Columns]
-        assert image.GetPhotometricInterpretation().GetType() == \
-            gdcm.PhotometricInterpretation.GetPIType(
-                dataset_2d.PhotometricInterpretation)
-        assert image.GetTransferSyntax().GetString() == str.__str__(
-            dataset_2d.file_meta.TransferSyntaxUID)
+        assert 2 == image.GetNumberOfDimensions()
+        assert [dataset_2d.Rows, dataset_2d.Columns] == image.GetDimensions()
+        pi_type = gdcm.PhotometricInterpretation.GetPIType(
+            dataset_2d.PhotometricInterpretation
+        )
+        assert pi_type == image.GetPhotometricInterpretation().GetType()
+
+        uid = str.__str__(dataset_2d.file_meta.TransferSyntaxUID)
+        assert uid == image.GetTransferSyntax().GetString()
         pixel_format = image.GetPixelFormat()
-        assert pixel_format.GetSamplesPerPixel() == dataset_2d.SamplesPerPixel
-        assert pixel_format.GetBitsAllocated() == dataset_2d.BitsAllocated
-        assert pixel_format.GetBitsStored() == dataset_2d.BitsStored
-        assert pixel_format.GetHighBit() == dataset_2d.HighBit
-        assert pixel_format.GetPixelRepresentation() ==\
-            dataset_2d.PixelRepresentation
+        assert dataset_2d.SamplesPerPixel == pixel_format.GetSamplesPerPixel()
+        assert dataset_2d.BitsAllocated == pixel_format.GetBitsAllocated()
+        assert dataset_2d.BitsStored == pixel_format.GetBitsStored()
+        assert dataset_2d.HighBit == pixel_format.GetHighBit()
+        px_repr = dataset_2d.PixelRepresentation
+        assert px_repr == pixel_format.GetPixelRepresentation()
 
     @pytest.mark.skipif(not HAVE_GDCM_IN_MEMORY_SUPPORT,
                         reason=gdcm_im_missing_message)
     def test_create_image_from_3d_dataset(self, dataset_3d):
         data_element = gdcm_handler.create_data_element(dataset_3d)
         image = gdcm_handler.create_image(dataset_3d, data_element)
-        assert image.GetNumberOfDimensions() == 3
-        assert image.GetDimensions() == [
+        assert 3 == image.GetNumberOfDimensions()
+        assert [
             dataset_3d.Columns, dataset_3d.Rows,
-            int(dataset_3d.NumberOfFrames)]
-        assert image.GetPhotometricInterpretation().GetType() == \
-            gdcm.PhotometricInterpretation.GetPIType(
-                dataset_3d.PhotometricInterpretation)
-        assert image.GetTransferSyntax().GetString() == str.__str__(
-            dataset_3d.file_meta.TransferSyntaxUID)
+            int(dataset_3d.NumberOfFrames)
+        ] == image.GetDimensions()
+        pi = gdcm.PhotometricInterpretation.GetPIType(
+            dataset_3d.PhotometricInterpretation
+        )
+        assert pi == image.GetPhotometricInterpretation().GetType()
+        uid = str.__str__(dataset_3d.file_meta.TransferSyntaxUID)
+        assert uid == image.GetTransferSyntax().GetString()
         pixel_format = image.GetPixelFormat()
-        assert pixel_format.GetSamplesPerPixel() == dataset_3d.SamplesPerPixel
-        assert pixel_format.GetBitsAllocated() == dataset_3d.BitsAllocated
-        assert pixel_format.GetBitsStored() == dataset_3d.BitsStored
-        assert pixel_format.GetHighBit() == dataset_3d.HighBit
-        assert pixel_format.GetPixelRepresentation() ==\
-            dataset_3d.PixelRepresentation
-        assert image.GetPlanarConfiguration() ==\
-            dataset_3d.PlanarConfiguration
+        assert dataset_3d.SamplesPerPixel == pixel_format.GetSamplesPerPixel()
+        assert dataset_3d.BitsAllocated == pixel_format.GetBitsAllocated()
+        assert dataset_3d.BitsStored == pixel_format.GetBitsStored()
+        assert dataset_3d.HighBit == pixel_format.GetHighBit()
+        px_repr = dataset_3d.PixelRepresentation
+        assert px_repr == pixel_format.GetPixelRepresentation()
+        planar = dataset_3d.PlanarConfiguration
+        assert planar == image.GetPlanarConfiguration()
 
     @pytest.mark.skipif(not HAVE_GDCM, reason=gdcm_missing_message)
     def test_create_image_reader_with_string(self):
diff --git a/pydicom/tests/test_jpeg_ls_pixel_data.py b/pydicom/tests/test_jpeg_ls_pixel_data.py
index e7f0a4eda..b64cc3943 100644
--- a/pydicom/tests/test_jpeg_ls_pixel_data.py
+++ b/pydicom/tests/test_jpeg_ls_pixel_data.py
@@ -1,29 +1,24 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
+"""Unit tests for the JPEG-LS Pixel Data handler."""
 
-import unittest
 import os
 import sys
+
 import pytest
+
 import pydicom
 from pydicom.filereader import dcmread
 from pydicom.data import get_testdata_files
+
 jpeg_ls_missing_message = ("jpeg_ls is not available "
                            "in this test environment")
 jpeg_ls_present_message = "jpeg_ls is being tested"
 
-try:
-    import pydicom.pixel_data_handlers.numpy_handler as numpy_handler
-    have_numpy_handler = numpy_handler.HAVE_NP
-except ImportError:
-    have_numpy_handler = False
-    numpy_handler = None
+from pydicom.pixel_data_handlers import numpy_handler
+have_numpy_handler = numpy_handler.is_available()
 
-try:
-    import pydicom.pixel_data_handlers.jpeg_ls_handler as jpeg_ls_handler
-    have_jpeg_ls_handler = jpeg_ls_handler.HAVE_JPEGLS
-except ImportError:
-    have_jpeg_ls_handler = False
-    jpeg_ls_handler = None
+from pydicom.pixel_data_handlers import jpeg_ls_handler
+have_jpeg_ls_handler = jpeg_ls_handler.is_available()
 
 test_jpeg_ls_decoder = have_numpy_handler and have_jpeg_ls_handler
 
@@ -69,8 +64,8 @@ dir_name = os.path.dirname(sys.argv[0])
 save_dir = os.getcwd()
 
 
-class jpeg_ls_JPEG_LS_Tests_no_jpeg_ls(unittest.TestCase):
-    def setUp(self):
+class TestJPEGLS_no_jpeg_ls(object):
+    def setup(self):
         self.jpeg_ls_lossless = dcmread(jpeg_ls_lossless_name)
         self.mr_small = dcmread(mr_name)
         self.emri_jpeg_ls_lossless = dcmread(emri_jpeg_ls_lossless)
@@ -78,16 +73,16 @@ class jpeg_ls_JPEG_LS_Tests_no_jpeg_ls(unittest.TestCase):
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def test_JPEG_LS_PixelArray(self):
-        with self.assertRaises((RuntimeError, NotImplementedError)):
-            _ = self.jpeg_ls_lossless.pixel_array
+        with pytest.raises((RuntimeError, NotImplementedError)):
+            self.jpeg_ls_lossless.pixel_array
 
 
-class jpeg_ls_JPEG2000Tests_no_jpeg_ls(unittest.TestCase):
-    def setUp(self):
+class TestJPEGLS_JPEG2000_no_jpeg_ls(object):
+    def setup(self):
         self.jpeg_2k = dcmread(jpeg2000_name)
         self.jpeg_2k_lossless = dcmread(jpeg2000_lossless_name)
         self.mr_small = dcmread(mr_name)
@@ -96,58 +91,52 @@ class jpeg_ls_JPEG2000Tests_no_jpeg_ls(unittest.TestCase):
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def test_JPEG2000PixelArray(self):
         """JPEG2000: Now works"""
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_2k.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_2k.pixel_array
 
     def test_emri_JPEG2000PixelArray(self):
         """JPEG2000: Now works"""
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_2k_lossless.pixel_array
-
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_2k_lossless.pixel_array
 
-class jpeg_ls_JPEGlossyTests_no_jpeg_ls(unittest.TestCase):
 
-    def setUp(self):
+class TestJPEGLS_JPEGlossy_no_jpeg_ls(object):
+    def setup(self):
         self.jpeg_lossy = dcmread(jpeg_lossy_name)
         self.color_3d_jpeg = dcmread(color_3d_jpeg_baseline)
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def testJPEGlossy(self):
         """JPEG-lossy: Returns correct values for sample data elements"""
         got = self.jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossy file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert 'Lossy Compression' == got
 
     def testJPEGlossyPixelArray(self):
         """JPEG-lossy: Fails gracefully when uncompressed data is asked for"""
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossy.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossy.pixel_array
 
     def testJPEGBaselineColor3DPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.color_3d_jpeg.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.color_3d_jpeg.pixel_array
 
 
-class jpeg_ls_JPEGlosslessTests_no_jpeg_ls(unittest.TestCase):
-    def setUp(self):
+class TestJPEGLS_JPEGlossless_no_jpeg_ls(object):
+    def setup(self):
         self.jpeg_lossless = dcmread(jpeg_lossless_name)
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def testJPEGlossless(self):
@@ -156,24 +145,17 @@ class jpeg_ls_JPEGlosslessTests_no_jpeg_ls(unittest.TestCase):
             jpeg_lossless.\
             SourceImageSequence[0].\
             PurposeOfReferenceCodeSequence[0].CodeMeaning
-        expected = 'Uncompressed predecessor'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossless file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert 'Uncompressed predecessor' == got
 
     def testJPEGlosslessPixelArray(self):
         """JPEGlossless: Fails gracefully when uncompressed data asked for"""
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossless.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossless.pixel_array
 
 
-@pytest.mark.skipif(
-    not test_jpeg_ls_decoder,
-    reason=jpeg_ls_missing_message)
-class jpeg_ls_JPEG_LS_Tests_with_jpeg_ls(unittest.TestCase):
-    def setUp(self):
+@pytest.mark.skipif(not test_jpeg_ls_decoder, reason=jpeg_ls_missing_message)
+class TestJPEGLS_JPEG_LS_with_jpeg_ls(object):
+    def setup(self):
         self.jpeg_ls_lossless = dcmread(jpeg_ls_lossless_name)
         self.mr_small = dcmread(mr_name)
         self.emri_jpeg_ls_lossless = dcmread(emri_jpeg_ls_lossless)
@@ -181,42 +163,30 @@ class jpeg_ls_JPEG_LS_Tests_with_jpeg_ls(unittest.TestCase):
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [jpeg_ls_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def test_raises_if_endianess_not_set(self):
         self.jpeg_ls_lossless.is_little_endian = None
         with pytest.raises(ValueError):
-            _ = self.jpeg_ls_lossless.pixel_array
+            self.jpeg_ls_lossless.pixel_array
 
     def test_JPEG_LS_PixelArray(self):
         a = self.jpeg_ls_lossless.pixel_array
         b = self.mr_small.pixel_array
-        self.assertEqual(
-            a.mean(),
-            b.mean(),
-            "Decoded pixel data is not all {0} "
-            "(mean == {1})".format(b.mean(), a.mean()))
-
+        assert b.mean() == a.mean()
         assert a.flags.writeable
 
     def test_emri_JPEG_LS_PixelArray(self):
         a = self.emri_jpeg_ls_lossless.pixel_array
         b = self.emri_small.pixel_array
-        self.assertEqual(
-            a.mean(),
-            b.mean(),
-            "Decoded pixel data is not all {0} "
-            "(mean == {1})".format(b.mean(), a.mean()))
-
+        assert b.mean() == a.mean()
         assert a.flags.writeable
 
 
-@pytest.mark.skipif(
-    not test_jpeg_ls_decoder,
-    reason=jpeg_ls_missing_message)
-class jpeg_ls_JPEG2000Tests_with_jpeg_ls(unittest.TestCase):
-    def setUp(self):
+@pytest.mark.skipif(not test_jpeg_ls_decoder, reason=jpeg_ls_missing_message)
+class TestJPEGLS_JPEG2000_with_jpeg_ls(object):
+    def setup(self):
         self.jpeg_2k = dcmread(jpeg2000_name)
         self.jpeg_2k_lossless = dcmread(jpeg2000_lossless_name)
         self.mr_small = dcmread(mr_name)
@@ -225,61 +195,51 @@ class jpeg_ls_JPEG2000Tests_with_jpeg_ls(unittest.TestCase):
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [jpeg_ls_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def test_JPEG2000PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_2k.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_2k.pixel_array
 
     def test_emri_JPEG2000PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_2k_lossless.pixel_array
-
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_2k_lossless.pixel_array
 
-@pytest.mark.skipif(
-    not test_jpeg_ls_decoder,
-    reason=jpeg_ls_missing_message)
-class jpeg_ls_JPEGlossyTests_with_jpeg_ls(unittest.TestCase):
 
-    def setUp(self):
+@pytest.mark.skipif(not test_jpeg_ls_decoder, reason=jpeg_ls_missing_message)
+class TestJPEGLS_JPEGlossy_with_jpeg_ls(object):
+    def setup(self):
         self.jpeg_lossy = dcmread(jpeg_lossy_name)
         self.color_3d_jpeg = dcmread(color_3d_jpeg_baseline)
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [jpeg_ls_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def testJPEGlossy(self):
         """JPEG-lossy: Returns correct values for sample data elements"""
         got = self.jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossy file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert 'Lossy Compression' == got
 
     def testJPEGlossyPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossy.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossy.pixel_array
 
     def testJPEGBaselineColor3DPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.color_3d_jpeg.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.color_3d_jpeg.pixel_array
 
 
-@pytest.mark.skipif(
-    not test_jpeg_ls_decoder,
-    reason=jpeg_ls_missing_message)
-class jpeg_ls_JPEGlosslessTests_with_jpeg_ls(unittest.TestCase):
-    def setUp(self):
+@pytest.mark.skipif(not test_jpeg_ls_decoder, reason=jpeg_ls_missing_message)
+class TestJPEGLS_JPEGlossless_with_jpeg_ls(object):
+    def setup(self):
         self.jpeg_lossless = dcmread(jpeg_lossless_name)
         self.original_handlers = pydicom.config.pixel_data_handlers
         pydicom.config.pixel_data_handlers = [jpeg_ls_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
         pydicom.config.pixel_data_handlers = self.original_handlers
 
     def testJPEGlossless(self):
@@ -288,14 +248,9 @@ class jpeg_ls_JPEGlosslessTests_with_jpeg_ls(unittest.TestCase):
             jpeg_lossless.\
             SourceImageSequence[0].\
             PurposeOfReferenceCodeSequence[0].CodeMeaning
-        expected = 'Uncompressed predecessor'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossless file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert 'Uncompressed predecessor' == got
 
     def testJPEGlosslessPixelArray(self):
         """JPEGlossless: Fails gracefully when uncompressed data asked for"""
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossless.pixel_array
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossless.pixel_array
diff --git a/pydicom/tests/test_multival.py b/pydicom/tests/test_multival.py
index 206ce08be..8e585f99c 100644
--- a/pydicom/tests/test_multival.py
+++ b/pydicom/tests/test_multival.py
@@ -1,43 +1,46 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""Test suite for MultiValue class"""
+"""Unit tests for the pydicom.multival module."""
 
-import unittest
+import pytest
 from pydicom.multival import MultiValue
 from pydicom.valuerep import DS, DSfloat, DSdecimal, IS
-from pydicom import config
+from pydicom import config, compat
 from copy import deepcopy
 
 import sys
+
 python_version = sys.version_info
 
 
-class MultiValuetests(unittest.TestCase):
+class TestMultiValue(object):
     def testMultiDS(self):
         """MultiValue: Multi-valued data elements can be created........"""
         multival = MultiValue(DS, ['11.1', '22.2', '33.3'])
         for val in multival:
-            self.assertTrue(isinstance(val, (DSfloat, DSdecimal)),
-                            "Multi-value DS item not converted to DS")
+            assert isinstance(val, (DSfloat, DSdecimal))
 
     def testEmptyElements(self):
         """MultiValue: Empty number string elements are not converted..."""
         multival = MultiValue(DSfloat, ['1.0', ''])
-        self.assertEqual(1.0, multival[0])
-        self.assertEqual('', multival[1])
+        assert 1.0 == multival[0]
+        assert '' == multival[1]
         multival = MultiValue(IS, ['1', ''])
-        self.assertEqual(1, multival[0])
-        self.assertEqual('', multival[1])
+        assert 1 == multival[0]
+        assert '' == multival[1]
         multival = MultiValue(DSdecimal, ['1', ''])
-        self.assertEqual(1, multival[0])
-        self.assertEqual('', multival[1])
+        assert 1 == multival[0]
+        assert '' == multival[1]
+
+        multival = MultiValue(IS, [])
+        assert not multival
+        assert 0 == len(multival)
 
     def testLimits(self):
         """MultiValue: Raise error if any item outside DICOM limits...."""
         original_flag = config.enforce_valid_values
         config.enforce_valid_values = True
-        self.assertRaises(OverflowError,
-                          MultiValue,
-                          IS, [1, -2 ** 31 - 1])
+        with pytest.raises(OverflowError):
+            MultiValue(IS, [1, -2 ** 31 - 1])
         # Overflow error not raised for IS out of DICOM valid range
         config.enforce_valid_values = original_flag
 
@@ -45,44 +48,39 @@ class MultiValuetests(unittest.TestCase):
         """MultiValue: Append of item converts it to required type..."""
         multival = MultiValue(IS, [1, 5, 10])
         multival.append('5')
-        self.assertTrue(isinstance(multival[-1], IS))
-        self.assertEqual(multival[-1], 5,
-                         "Item set by append is not correct value")
+        assert isinstance(multival[-1], IS)
+        assert 5 == multival[-1]
 
     def testSetIndex(self):
         """MultiValue: Setting list item converts it to required type"""
         multival = MultiValue(IS, [1, 5, 10])
         multival[1] = '7'
-        self.assertTrue(isinstance(multival[1], IS))
-        self.assertEqual(multival[1], 7,
-                         "Item set by index is not correct value")
+        assert isinstance(multival[1], IS)
+        assert 7 == multival[1]
 
     def testDeleteIndex(self):
         """MultiValue: Deleting item at index behaves as expected..."""
         multival = MultiValue(IS, [1, 5, 10])
         del multival[1]
-        self.assertEqual(2, len(multival))
-        self.assertEqual(multival[0], 1)
-        self.assertEqual(multival[1], 10)
+        assert 2 == len(multival)
+        assert 1 == multival[0]
+        assert 10 == multival[1]
 
     def testExtend(self):
         """MultiValue: Extending a list converts all to required type"""
         multival = MultiValue(IS, [1, 5, 10])
         multival.extend(['7', 42])
-        self.assertTrue(isinstance(multival[-2], IS))
-        self.assertTrue(isinstance(multival[-1], IS))
-        self.assertEqual(multival[-2], 7,
-                         "Item set by extend not correct value")
+        assert isinstance(multival[-2], IS)
+        assert isinstance(multival[-1], IS)
+        assert 7 == multival[-2]
 
     def testSlice(self):
         """MultiValue: Setting slice converts items to required type."""
         multival = MultiValue(IS, range(7))
         multival[2:7:2] = [4, 16, 36]
         for val in multival:
-            self.assertTrue(isinstance(val, IS),
-                            "Slice IS value not correct type")
-        self.assertEqual(multival[4], 16,
-                         "Set by slice failed for item 4 of list")
+            assert isinstance(val, IS)
+        assert 16 == multival[4]
 
     def testIssue236DeepCopy(self):
         """MultiValue: deepcopy of MultiValue does not generate an error"""
@@ -97,38 +95,45 @@ class MultiValuetests(unittest.TestCase):
         """MultiValue: allow inline sort."""
         multival = MultiValue(DS, [12, 33, 5, 7, 1])
         multival.sort()
-        self.assertEqual([1, 5, 7, 12, 33], multival)
+        assert [1, 5, 7, 12, 33] == multival
         multival.sort(reverse=True)
-        self.assertEqual([33, 12, 7, 5, 1], multival)
+        assert [33, 12, 7, 5, 1] == multival
         multival.sort(key=str)
-        self.assertEqual([1, 12, 33, 5, 7], multival)
+        assert [1, 12, 33, 5, 7] == multival
 
     def test_equal(self):
         """MultiValue: test equality operator"""
         multival = MultiValue(DS, [12, 33, 5, 7, 1])
         multival2 = MultiValue(DS, [12, 33, 5, 7, 1])
         multival3 = MultiValue(DS, [33, 12, 5, 7, 1])
-        self.assertTrue(multival == multival2)
-        self.assertFalse(multival == multival3)
+        assert multival == multival2
+        assert not (multival == multival3)
         multival = MultiValue(str, ['a', 'b', 'c'])
         multival2 = MultiValue(str, ['a', 'b', 'c'])
         multival3 = MultiValue(str, ['b', 'c', 'a'])
-        self.assertTrue(multival == multival2)
-        self.assertFalse(multival == multival3)
+        assert multival == multival2
+        assert not (multival == multival3)
 
     def test_not_equal(self):
         """MultiValue: test equality operator"""
         multival = MultiValue(DS, [12, 33, 5, 7, 1])
         multival2 = MultiValue(DS, [12, 33, 5, 7, 1])
         multival3 = MultiValue(DS, [33, 12, 5, 7, 1])
-        self.assertFalse(multival != multival2)
-        self.assertTrue(multival != multival3)
+        assert not multival != multival2
+        assert multival != multival3
         multival = MultiValue(str, ['a', 'b', 'c'])
         multival2 = MultiValue(str, ['a', 'b', 'c'])
         multival3 = MultiValue(str, ['b', 'c', 'a'])
-        self.assertFalse(multival != multival2)
-        self.assertTrue(multival != multival3)
-
-
-if __name__ == "__main__":
-    unittest.main()
+        assert not (multival != multival2)
+        assert multival != multival3
+
+    def test_str_rep(self):
+        """MultiValue: test print output"""
+        multival = MultiValue(IS, [])
+        assert '' == str(multival)
+        multival = MultiValue(compat.text_type, [1, 2, 3])
+        assert "['1', '2', '3']" == str(multival)
+        multival = MultiValue(int, [1, 2, 3])
+        assert '[1, 2, 3]' == str(multival)
+        multival = MultiValue(float, [1.1, 2.2, 3.3])
+        assert '[1.1, 2.2, 3.3]' == str(multival)
diff --git a/pydicom/tests/test_rawread.py b/pydicom/tests/test_rawread.py
index 4f4e54785..ec47e29d8 100644
--- a/pydicom/tests/test_rawread.py
+++ b/pydicom/tests/test_rawread.py
@@ -1,19 +1,20 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""unittest tests for pydicom.filereader module -- simple raw data elements"""
+"""Unit tests for the pydicom.filereader module using raw data elements."""
 
 from io import BytesIO
-import unittest
+
+import pytest
+
 from pydicom.filereader import data_element_generator
 from pydicom.values import convert_value
 from pydicom.sequence import Sequence
 from pydicom.util.hexutil import hex2bytes
 
 
-class RawReaderExplVRTests(unittest.TestCase):
+class TestRawReaderExplVRTests(object):
     # See comments in data_element_generator
     # summary of DICOM data element formats
     # Here we are trying to test all those variations
-
     def testExplVRLittleEndianLongLength(self):
         """Raw read: Explicit VR Little Endian long length..."""
         # (0002,0001) OB 2-byte-reserved 4-byte-length, value 0x00 0x01
@@ -26,12 +27,7 @@ class RawReaderExplVRTests(unittest.TestCase):
         de_gen = data_element_generator(infile,
                                         is_implicit_VR=False,
                                         is_little_endian=True)
-        got = next(de_gen)
-        msg_loc = "in read of Explicit VR='OB'"
-        msg_loc = "%s data element (long length format)" % (msg_loc)
-        self.assertEqual(got, expected,
-                         "Expected: %r, got %r in %s"
-                         % (expected, got, msg_loc))
+        assert expected == next(de_gen)
         # (0002,0002) OB 2-byte-reserved 4-byte-length,
         # value 0x00 0x01
 
@@ -47,12 +43,7 @@ class RawReaderExplVRTests(unittest.TestCase):
         de_gen = data_element_generator(infile,
                                         is_implicit_VR=False,
                                         is_little_endian=True)
-        got = next(de_gen)
-        msg_loc = "in read of Explicit VR='IS'"
-        msg_loc = "%s data element (short length format)" % (msg_loc)
-        self.assertEqual(got, expected,
-                         "Expected: %r, got %r in %s"
-                         % (expected, got, msg_loc))
+        assert expected == next(de_gen)
 
     def testExplVRLittleEndianUndefLength(self):
         """Raw read: Expl VR Little Endian with undefined length..."""
@@ -69,11 +60,7 @@ class RawReaderExplVRTests(unittest.TestCase):
         de_gen = data_element_generator(infile,
                                         is_implicit_VR=False,
                                         is_little_endian=True)
-        got = next(de_gen)
-        msg_loc = "in read of undefined length Explicit VR ='OB' short value)"
-        self.assertEqual(got, expected,
-                         "Expected: %r, got %r in %s"
-                         % (expected, got, msg_loc))
+        assert expected == next(de_gen)
 
         # Test again such that delimiter crosses default 128-byte "chunks"
         for multiplier in (116, 117, 118, 120):
@@ -87,17 +74,11 @@ class RawReaderExplVRTests(unittest.TestCase):
                                             is_little_endian=True)
             got = next(de_gen)
             got_len = len(got.value)
-            msg_loc = "in read of undefined length Explicit VR ='OB'"
-            msg_loc = "%s with 'multiplier' %d" % (msg_loc, multiplier)
-            self.assertEqual(expected, got_len,
-                             "Expected value length %d, got %d in %s"
-                             % (expected, got_len, msg_loc))
-            msg = "Unexpected value start with multiplier %d" % (multiplier)
-            msg = "%s on Expl VR undefined length" % (msg)
-            self.assertTrue(got.value.startswith(b'ABCDEFGHIJ\0'), msg)
+            assert expected == got_len
+            assert got.value.startswith(b'ABCDEFGHIJ\0')
 
 
-class RawReaderImplVRTests(unittest.TestCase):
+class TestRawReaderImplVR(object):
     # See comments in data_element_generator
     # summary of DICOM data element formats
     # Here we are trying to test all those variations
@@ -114,12 +95,7 @@ class RawReaderImplVRTests(unittest.TestCase):
         de_gen = data_element_generator(infile,
                                         is_implicit_VR=True,
                                         is_little_endian=True)
-        got = next(de_gen)
-        msg_loc = "in read of Implicit VR='IS'"
-        msg_loc = "%s data element (short length format)" % (msg_loc)
-        self.assertEqual(got, expected,
-                         "Expected: %r, got %r in %s"
-                         % (expected, got, msg_loc))
+        assert expected == next(de_gen)
 
     def testImplVRLittleEndianUndefLength(self):
         """Raw read: Impl VR Little Endian with undefined length..."""
@@ -135,12 +111,7 @@ class RawReaderImplVRTests(unittest.TestCase):
         de_gen = data_element_generator(infile,
                                         is_implicit_VR=True,
                                         is_little_endian=True)
-        got = next(de_gen)
-        msg_loc = "in read of undefined length Implicit VR ='OB' short value)"
-        self.assertEqual(got, expected,
-                         "Expected: %r, got %r in %s" % (expected,
-                                                         got,
-                                                         msg_loc))
+        assert expected == next(de_gen)
 
         # Test again such that delimiter crosses default 128-byte "chunks"
         for multiplier in (116, 117, 118, 120):
@@ -153,19 +124,11 @@ class RawReaderImplVRTests(unittest.TestCase):
                                             is_implicit_VR=True,
                                             is_little_endian=True)
             got = next(de_gen)
-            got_len = len(got.value)
-            msg_loc = "in read of undefined length Implicit VR"
-            msg_loc = "%s with 'multiplier' %d" % (msg_loc, multiplier)
-            self.assertEqual(expected, got_len,
-                             "Expected value length %d, got %d in %s"
-                             % (expected, got_len, msg_loc))
+            assert expected == len(got.value)
+            assert got.value.startswith(b'ABCDEFGHIJ\0')
 
-            msg = "Unexpected value start with multiplier %d" % (multiplier)
-            msg = "%s on Implicit VR undefined length" % (msg)
-            self.assertTrue(got.value.startswith(b'ABCDEFGHIJ\0'), msg)
 
-
-class RawSequenceTests(unittest.TestCase):
+class TestRawSequence(object):
     # See DICOM standard PS3.5-2008 section 7.5 for sequence syntax
     def testEmptyItem(self):
         """Read sequence with a single empty item..."""
@@ -192,19 +155,11 @@ class RawSequenceTests(unittest.TestCase):
                                      is_little_endian=True)
         raw_seq = next(gen)
         seq = convert_value("SQ", raw_seq)
-
-        got_type = "got type {0}".format(str(type(seq)))
-        self.assertTrue(isinstance(seq, Sequence),
-                        "Did not get Sequence, %s" % got_type)
-        expected = "Expected Sequence with single (empty) item"
-        got = "got {0:d} item(s)".format(len(seq))
-        self.assertTrue(len(seq) == 1, "%s, %s" % (expected, got))
-        msg = "Expected the sequence item (dataset) to be empty"
-        self.assertTrue(len(seq[0]) == 0, msg)
+        assert isinstance(seq, Sequence)
+        assert 1 == len(seq)
+        assert 0 == len(seq[0])
         elem2 = next(gen)
-        self.assertEqual(elem2.tag,
-                         0x0008103e,
-                         "Expected a data element after empty sequence item")
+        assert 0x0008103e == elem2.tag
 
     def testImplVRLittleEndian_ExplicitLengthSeq(self):
         """Raw read: ImplVR Little Endian SQ with explicit lengths..."""
@@ -241,12 +196,8 @@ class RawSequenceTests(unittest.TestCase):
 
         # The sequence is parsed, but only into raw data elements.
         # They will be converted when asked for. Check some:
-        got = seq[0].BeamNumber
-        self.assertTrue(got == 1,
-                        "Expected Beam Number 1, got {0!r}".format(got))
-        got = seq[1].BeamName
-        self.assertTrue(got == 'Beam 2',
-                        "Expected Beam Name 'Beam 2', got {0:s}".format(got))
+        assert 1 == seq[0].BeamNumber
+        assert 'Beam 2' == seq[1].BeamName
 
     def testImplVRBigEndian_ExplicitLengthSeq(self):
         """Raw read: ImplVR BigEndian SQ with explicit lengths..."""
@@ -283,12 +234,8 @@ class RawSequenceTests(unittest.TestCase):
 
         # The sequence is parsed, but only into raw data elements.
         # They will be converted when asked for. Check some:
-        got = seq[0].BeamNumber
-        self.assertTrue(got == 1,
-                        "Expected Beam Number 1, got {0!r}".format(got))
-        got = seq[1].BeamName
-        self.assertTrue(got == 'Beam 2',
-                        "Expected Beam Name 'Beam 2', got {0:s}".format(got))
+        assert 1 == seq[0].BeamNumber
+        assert 'Beam 2' == seq[1].BeamName
 
     def testExplVRBigEndian_UndefinedLengthSeq(self):
         """Raw read: ExplVR BigEndian Undefined Length SQ..."""
@@ -334,15 +281,5 @@ class RawSequenceTests(unittest.TestCase):
 
         # The sequence is parsed, but only into raw data elements.
         # They will be converted when asked for. Check some:
-        got = seq[0].BeamNumber
-        self.assertTrue(got == 1,
-                        "Expected Beam Number 1, got {0!r}".format(got))
-        got = seq[1].BeamName
-        self.assertTrue(got == 'Beam 2',
-                        "Expected Beam Name 'Beam 2', got {0:s}".format(got))
-
-
-if __name__ == "__main__":
-    # import pydicom
-    # pydicom.debug()
-    unittest.main()
+        assert 1 == seq[0].BeamNumber
+        assert 'Beam 2' == seq[1].BeamName
diff --git a/pydicom/tests/test_sequence.py b/pydicom/tests/test_sequence.py
index 75f26fd50..c2bbdcce8 100644
--- a/pydicom/tests/test_sequence.py
+++ b/pydicom/tests/test_sequence.py
@@ -1,16 +1,17 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""unittest cases for Sequence class"""
+"""Unit tests for the pydicom.sequence module."""
+
+import pytest
 
-import unittest
 from pydicom.dataset import Dataset
 from pydicom.sequence import Sequence
 
 
-class SequenceTests(unittest.TestCase):
+class TestSequence(object):
     def testDefaultInitialization(self):
         """Sequence: Ensure a valid Sequence is created"""
         empty = Sequence()
-        self.assertTrue(len(empty) == 0, "Non-empty Sequence created")
+        assert 0 == len(empty)
 
     def testValidInitialization(self):
         """Sequence: Ensure valid creation of Sequences using Dataset inputs"""
@@ -22,23 +23,26 @@ class SequenceTests(unittest.TestCase):
 
         # Construct the sequence
         seq = Sequence((patientSetups,))
-        self.assertTrue(isinstance(seq[0], Dataset),
-                        "Dataset modified during Sequence creation")
+        assert isinstance(seq[0], Dataset)
 
     def testInvalidInitialization(self):
         """Sequence: Raise error if inputs are not iterables or Datasets"""
         # Error on construction with single Dataset
-        self.assertRaises(TypeError, Sequence, Dataset())
+        with pytest.raises(TypeError):
+            Sequence(Dataset())
         # Test for non-iterable
-        self.assertRaises(TypeError, Sequence, 1)
+        with pytest.raises(TypeError):
+            Sequence(1)
         # Test for invalid iterable contents
-        self.assertRaises(TypeError, Sequence, [1, 2])
+        with pytest.raises(TypeError):
+            Sequence([1, 2])
 
     def testInvalidAssignment(self):
         """Sequence: validate exception for invalid assignment"""
         seq = Sequence([Dataset(), ])
         # Attempt to assign an integer to the first element
-        self.assertRaises(TypeError, seq.__setitem__, 0, 1)
+        with pytest.raises(TypeError):
+            seq.__setitem__(0, 1)
 
     def testValidAssignment(self):
         """Sequence: ensure ability to assign a Dataset to a Sequence item"""
@@ -49,7 +53,7 @@ class SequenceTests(unittest.TestCase):
         seq = Sequence([Dataset(), ])
         seq[0] = ds
 
-        self.assertEqual(seq[0], ds, "Dataset modified during assignment")
+        assert ds == seq[0]
 
     def test_str(self):
         """Test string output of the sequence"""
@@ -63,7 +67,3 @@ class SequenceTests(unittest.TestCase):
         assert "PN: 'TEST'" in out
         assert "(0010, 0020) Patient ID" in out
         assert "LO: '12345']" in out
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/pydicom/tests/test_tag.py b/pydicom/tests/test_tag.py
index 5460a6d7b..c1da921f2 100644
--- a/pydicom/tests/test_tag.py
+++ b/pydicom/tests/test_tag.py
@@ -1,7 +1,5 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
-"""Test suite for tag.py"""
-
-import unittest
+"""Unit tests for the pydicom.tag module."""
 
 import pytest
 
@@ -146,6 +144,7 @@ class TestBaseTag(object):
 
     def test_eq_diff_class(self):
         """Test __eq__ of two classes with different type."""
+        # Make sure to test BaseTag.__eq__() not int.__eq__()
         assert BaseTag(0x00000000) == 0
         assert not BaseTag(0x00000001) == 0
 
@@ -158,6 +157,7 @@ class TestBaseTag(object):
 
     def test_eq_tuple(self):
         """Test __eq__ of tuple with BaseTag."""
+        # Make sure to test BaseTag.__eq__() not tuple.__eq__()
         assert BaseTag(0x00010002) == (0x0001, 0x0002)
         assert not BaseTag(0x00010001) == (0x0001, 0x0002)
 
@@ -174,6 +174,7 @@ class TestBaseTag(object):
 
     def test_ne_diff_class(self):
         """Test __ne__ of two classes with different type."""
+        # Make sure to test BaseTag.__ne__() not int.__ne__()
         assert not BaseTag(0x00000000) != 0
         assert BaseTag(0x00000001) != 0
 
@@ -186,6 +187,7 @@ class TestBaseTag(object):
 
     def test_ne_tuple(self):
         """Test __ne__ of tuple with BaseTag."""
+        # Make sure to test BaseTag.__ne__() not tuple.__ne__()
         assert not BaseTag(0x00010002) != (0x0001, 0x0002)
         assert BaseTag(0x00010001) != (0x0001, 0x0002)
 
@@ -203,22 +205,22 @@ class TestBaseTag(object):
 
     def test_str(self):
         """Test str(BaseTag) produces correct value."""
-        assert str(BaseTag(0x00000000)) == '(0000, 0000)'
-        assert str(BaseTag(0x00010002)) == '(0001, 0002)'
-        assert str(BaseTag(0x10002000)) == '(1000, 2000)'
-        assert str(BaseTag(0xFFFFFFFE)) == '(ffff, fffe)'
+        assert '(0000, 0000)' == str(BaseTag(0x00000000))
+        assert '(0001, 0002)' == str(BaseTag(0x00010002))
+        assert '(1000, 2000)' == str(BaseTag(0x10002000))
+        assert '(ffff, fffe)' == str(BaseTag(0xFFFFFFFE))
 
     def test_group(self):
         """Test BaseTag.group returns correct values."""
-        assert BaseTag(0x00000001).group == 0x0000
-        assert BaseTag(0x00020001).group == 0x0002
-        assert BaseTag(0xFFFF0001).group == 0xFFFF
+        assert 0x0000 == BaseTag(0x00000001).group
+        assert 0x0002 == BaseTag(0x00020001).group
+        assert 0xFFFF == BaseTag(0xFFFF0001).group
 
     def test_element(self):
         """Test BaseTag.element returns correct values."""
-        assert BaseTag(0x00010000).element == 0x0000
-        assert BaseTag(0x00010002).element == 0x0002
-        assert BaseTag(0x0001FFFF).element == 0xFFFF
+        assert 0x0000 == BaseTag(0x00010000).element
+        assert 0x0002 == BaseTag(0x00010002).element
+        assert 0xFFFF == BaseTag(0x0001FFFF).element
 
     def test_private(self):
         """Test BaseTag.is_private returns correct values."""
@@ -321,7 +323,7 @@ class TestTag(object):
         pytest.raises(ValueError, Tag, ['0x01', '0x02'], '0x01')
         pytest.raises(ValueError, Tag, ['0x01', '0x02'], 0x01)
 
-    @unittest.skipIf(not in_py2, 'Long type only exists in Python 2')
+    @pytest.mark.skipif(not in_py2, reason='Long type only exists in Python 2')
     def test_mixed_long_int(self):
         assert Tag([0x1000, long(0x2000)]) == BaseTag(0x10002000)
         assert Tag([long(0x1000), 0x2000]) == BaseTag(0x10002000)
@@ -394,7 +396,3 @@ class TestTagInException(object):
             with tag_in_exception(tag) as tag:
                 raise ValueError('Test message.')
         pytest.raises(ValueError, test)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/pydicom/tests/test_unicode.py b/pydicom/tests/test_unicode.py
index a9daa382e..71ee93d6e 100644
--- a/pydicom/tests/test_unicode.py
+++ b/pydicom/tests/test_unicode.py
@@ -1,13 +1,16 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
 # -*- coding: utf-8 -*-
+"""Unit tests for unicode."""
 
 import sys
-import unittest
+
+import pytest
+
 from pydicom import dcmread
 
 
-class UnicodeFilenames(unittest.TestCase):
-    def testRead(self):
+class TestUnicodeFilenames(object):
+    def test_read(self):
         """Unicode: Can read a file with unicode characters in name..."""
         uni_name = u'test°'
 
@@ -25,7 +28,3 @@ class UnicodeFilenames(unittest.TestCase):
         # ignore file doesn't exist error
         except IOError:
             pass
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/pydicom/tests/test_util.py b/pydicom/tests/test_util.py
index 72c2f0ee8..508eb9fd6 100644
--- a/pydicom/tests/test_util.py
+++ b/pydicom/tests/test_util.py
@@ -3,7 +3,6 @@
 
 from io import BytesIO
 import os
-import unittest
 
 import pytest
 
@@ -35,7 +34,7 @@ class TestCodify(object):
         input_str = ['TheNameToConvert', 'Some12Variable_Name']
         output_str = ['the_name_to_convert', 'some12_variable__name']
         for in_str, out_str in zip(input_str, output_str):
-            assert camel_to_underscore(in_str) == out_str
+            assert out_str == camel_to_underscore(in_str)
 
     def test_tag_repr(self):
         """Test utils.codify.tag_repr"""
@@ -43,7 +42,7 @@ class TestCodify(object):
         output_str = ['(0x0000, 0x0000)', '(0x0010, 0x0010)',
                       '(0x7fe0, 0x0010)', '(0x1111, 0x0001)']
         for tag, out_str in zip(input_tag, output_str):
-            assert tag_repr(Tag(tag)) == out_str
+            assert out_str == tag_repr(Tag(tag))
 
     def test_default_name_filter(self):
         """Test utils.codify.default_name_filter"""
@@ -51,7 +50,7 @@ class TestCodify(object):
                          'FractionGroupThing']
         output_str = ['cp_set', 'ref_data_set', 'frxn_gp_thing']
         for in_str, out_str in zip(input_keyword, output_str):
-            assert default_name_filter(in_str) == out_str
+            assert out_str == default_name_filter(in_str)
 
     def test_code_imports(self):
         """Test utils.codify.code_imports"""
@@ -60,7 +59,7 @@ class TestCodify(object):
         out += 'import pydicom\n'
         out += 'from pydicom.dataset import Dataset\n'
         out += 'from pydicom.sequence import Sequence'
-        assert code_imports() == out
+        assert out == code_imports()
 
     def test_code_dataelem_standard(self):
         """Test utils.codify.code_dataelem for standard element"""
@@ -72,7 +71,7 @@ class TestCodify(object):
                    "ds.CodingSchemeUID = '1.1.2.3.4.5'",
                    "ds.PrivateGroupReference = 1200"]
         for elem, out in zip(input_elem, out_str):
-            assert code_dataelem(elem) == out
+            assert out == code_dataelem(elem)
 
     def test_code_dataelem_exclude_size(self):
         """Test utils.codify.code_dataelem exclude_size param"""
@@ -87,7 +86,7 @@ class TestCodify(object):
         # Fails
         # "ds.PrivateGroupReference = 1200"]
         for elem, out in zip(input_elem, out_str):
-            assert code_dataelem(elem, exclude_size=4) == out
+            assert out == code_dataelem(elem, exclude_size=4)
 
     def test_code_dataelem_private(self):
         """Test utils.codify.code_dataelem"""
@@ -99,7 +98,7 @@ class TestCodify(object):
                    "ds.add_new((0x0081, 0x010c), 'UI', '1.1.2.3.4.5')",
                    "ds.add_new((0x1111, 0x0301), 'US', 1200)"]
         for elem, out in zip(input_elem, out_str):
-            assert code_dataelem(elem) == out
+            assert out == code_dataelem(elem)
 
     def test_code_dataelem_sequence(self):
         """Test utils.codify.code_dataelem"""
@@ -108,7 +107,7 @@ class TestCodify(object):
         out = "\n# Control Point Sequence\n"
         out += "cp_sequence = Sequence()\n"
         out += "ds.ControlPointSequence = cp_sequence"
-        assert code_dataelem(elem) == out
+        assert out == code_dataelem(elem)
 
     def test_code_sequence(self):
         """Test utils.codify.code_dataelem"""
@@ -126,7 +125,7 @@ class TestCodify(object):
         out += "cp1.PatientID = '1234'\n"
         out += "cp_sequence.append(cp1)"
 
-        assert code_dataelem(elem) == out
+        assert out == code_dataelem(elem)
 
     def test_code_dataset(self):
         """Test utils.codify.code_dataset"""
@@ -146,13 +145,13 @@ class TestDump(object):
     def test_print_character(self):
         """Test utils.dump.print_character"""
         # assert print_character(0x30) == '0'  # Missing!
-        assert print_character(0x31) == '1'
-        assert print_character(0x39) == '9'
-        assert print_character(0x41) == 'A'
-        assert print_character(0x5A) == 'Z'
-        assert print_character(0x61) == 'a'
-        assert print_character(0x7A) == 'z'
-        assert print_character(0x00) == '.'
+        assert '1' == print_character(0x31)
+        assert '9' == print_character(0x39)
+        assert 'A' == print_character(0x41)
+        assert 'Z' == print_character(0x5A)
+        assert 'a' == print_character(0x61)
+        assert 'z' == print_character(0x7A)
+        assert '.' == print_character(0x00)
 
     def test_filedump(self):
         """Test utils.dump.filedump"""
@@ -217,16 +216,16 @@ class TestHexUtil(object):
         hexstring = "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"
         bytestring = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09' \
                      b'\x0A\x0B\x0C\x0D\x0E\x0F'
-        assert bytes2hex(bytestring) == hexstring
+        assert hexstring == bytes2hex(bytestring)
 
         hexstring = "00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0"
         bytestring = b'\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90' \
                      b'\xA0\xB0\xC0\xD0\xE0\xF0'
-        assert bytes2hex(bytestring) == hexstring
+        assert hexstring == bytes2hex(bytestring)
 
 
-class DataElementCallbackTests(unittest.TestCase):
-    def setUp(self):
+class TestDataElementCallbackTests(object):
+    def setup(self):
         # Set up a dataset with commas in one item instead of backslash
         config.enforce_valid_values = True
         namespace = {}
@@ -238,7 +237,7 @@ class DataElementCallbackTests(unittest.TestCase):
 
         self.bytesio = BytesIO(ds_bytes)
 
-    def tearDown(self):
+    def teardown(self):
         config.enforce_valid_values = False
 
     def testBadSeparator(self):
@@ -246,7 +245,8 @@ class DataElementCallbackTests(unittest.TestCase):
         ds = filereader.read_dataset(self.bytesio, is_little_endian=True,
                                      is_implicit_VR=True)
         contour = ds.ROIContourSequence[0].ContourSequence[0]
-        self.assertRaises(ValueError, getattr, contour, "ContourData")
+        with pytest.raises(ValueError):
+            getattr(contour, "ContourData")
 
     def testImplVRcomma(self):
         """util.fix_separator:
@@ -259,9 +259,4 @@ class DataElementCallbackTests(unittest.TestCase):
         got = ds.ROIContourSequence[0].ContourSequence[0].ContourData
         config.reset_data_element_callback()
 
-        msg = "Expected {0}, got {1}".format(expected, got)
-        self.assertEqual(expected, got, msg)
-
-
-if __name__ == "__main__":
-    unittest.main()
+        assert expected == got