diff --git a/setup.cfg b/setup.cfg
index 2a9acf1..a7da507 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,5 @@
 [bdist_wheel]
 universal = 1
+
+[tool:pytest]
+testpaths = tests
diff --git a/tests/local_tests.py b/tests/local_tests.py
deleted file mode 100644
index 850a737..0000000
--- a/tests/local_tests.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import spur
-
-from nose.tools import istest
-
-from .process_test_set import ProcessTestSet
-from .open_test_set import OpenTestSet
-
-
-class LocalTestMixin(object):
-    def create_shell(self):
-        return spur.LocalShell()
-    
-
-@istest
-class LocalOpenTests(OpenTestSet, LocalTestMixin):
-    pass
-
-
-@istest
-class LocalProcessTests(ProcessTestSet, LocalTestMixin):
-    pass
diff --git a/tests/test_local.py b/tests/test_local.py
new file mode 100644
index 0000000..468bcff
--- /dev/null
+++ b/tests/test_local.py
@@ -0,0 +1,22 @@
+import spur
+
+from .test_process_set import ProcessTestSet
+from .test_open_set import OpenTestSet
+
+
+class LocalTestMixin(object):
+    def create_shell(self):
+        return spur.LocalShell()
+
+
+
+class TestLocalOpenTests(OpenTestSet, LocalTestMixin):
+    pass
+
+
+
+class TestLocalProcessTests(ProcessTestSet, LocalTestMixin):
+    # Locally these produce FileNotFound Exceptions
+    test_spawning_non_existent_command_raises_specific_no_such_command_exception = None
+    test_spawning_command_that_uses_path_env_variable_asks_if_command_is_installed = None
+    test_using_non_existent_command_and_correct_cwd_raises_no_such_command_exception = None
diff --git a/tests/open_test_set.py b/tests/test_open_set.py
similarity index 64%
rename from tests/open_test_set.py
rename to tests/test_open_set.py
index ae3805a..c248e69 100644
--- a/tests/open_test_set.py
+++ b/tests/test_open_set.py
@@ -3,56 +3,54 @@
 import uuid
 import functools
 
-from nose.tools import assert_equal, istest, nottest
+import pytest
 
 __all__ = ["OpenTestSet"]
 
 
-@nottest
-def test(test_func):
+def wrapper(test_func):
     @functools.wraps(test_func)
-    @istest
     def run_test(self, *args, **kwargs):
         with self.create_shell() as shell:
             test_func(shell)
-    
+
     return run_test
 
 
 class OpenTestSet(object):
-    @test
-    def can_write_to_files_opened_by_open(shell):
+    @wrapper
+    def test_can_write_to_files_opened_by_open(shell):
         path = "/tmp/{0}".format(uuid.uuid4())
         f = shell.open(path, "w")
         try:
             f.write("hello")
             f.flush()
-            assert_equal(b"hello", shell.run(["cat", path]).output)
+            assert b"hello" == shell.run(["cat", path]).output
         finally:
             f.close()
             shell.run(["rm", path])
-            
-    @test
-    def can_read_files_opened_by_open(shell):
+
+    @wrapper
+    def test_can_read_files_opened_by_open(shell):
         path = "/tmp/{0}".format(uuid.uuid4())
         shell.run(["sh", "-c", "echo hello > '{0}'".format(path)])
         f = shell.open(path)
         try:
-            assert_equal("hello\n", f.read())
+            assert "hello\n" == f.read()
         finally:
             f.close()
             shell.run(["rm", path])
-            
-    @test
-    def open_can_be_used_as_context_manager(shell):
+
+    @wrapper
+    def test_open_can_be_used_as_context_manager(shell):
         path = "/tmp/{0}".format(uuid.uuid4())
         shell.run(["sh", "-c", "echo hello > '{0}'".format(path)])
         with shell.open(path) as f:
-            assert_equal("hello\n", f.read())
-            
-    @test
-    def files_can_be_opened_in_binary_mode(shell):
+            assert "hello\n" == f.read()
+
+    @wrapper
+    def test_files_can_be_opened_in_binary_mode(shell):
         path = "/tmp/{0}".format(uuid.uuid4())
         shell.run(["sh", "-c", "echo hello > '{0}'".format(path)])
         with shell.open(path, "rb") as f:
-            assert_equal(b"hello\n", f.read())
+            assert b"hello\n" == f.read()
diff --git a/tests/process_test_set.py b/tests/test_process_set.py
similarity index 50%
rename from tests/process_test_set.py
rename to tests/test_process_set.py
index 5381100..0b5ff31 100644
--- a/tests/process_test_set.py
+++ b/tests/test_process_set.py
@@ -7,18 +7,15 @@
 import functools
 import posixpath
 
-from nose.tools import istest, nottest, assert_equal, assert_not_equal, assert_raises, assert_true
-
 import spur
 
+import pytest
 
 __all__ = ["ProcessTestSet"]
 
 
-@nottest
-def test(test_func):
+def wrapper(test_func):
     @functools.wraps(test_func)
-    @istest
     def run_test(self, *args, **kwargs):
         with self.create_shell() as shell:
             test_func(shell)
@@ -27,315 +24,302 @@ def run_test(self, *args, **kwargs):
 
 
 class ProcessTestSet(object):
-    @test
-    def output_of_run_is_stored(shell):
+    @wrapper
+    def test_output_of_run_is_stored(shell):
         result = shell.run(["echo", "hello"])
-        assert_equal(b"hello\n", result.output)
+        assert b"hello\n" == result.output
 
-    @test
-    def output_is_not_truncated_when_not_ending_in_a_newline(shell):
+    @wrapper
+    def test_output_is_not_truncated_when_not_ending_in_a_newline(shell):
         result = shell.run(["echo", "-n", "hello"])
-        assert_equal(b"hello", result.output)
+        assert b"hello" == result.output
 
-    @test
-    def trailing_newlines_are_not_stripped_from_run_output(shell):
+    @wrapper
+    def test_trailing_newlines_are_not_stripped_from_run_output(shell):
         result = shell.run(["echo", "\n\n"])
-        assert_equal(b"\n\n\n", result.output)
+        assert b"\n\n\n" == result.output
 
-    @test
-    def stderr_output_of_run_is_stored(shell):
+    @wrapper
+    def test_stderr_output_of_run_is_stored(shell):
         result = shell.run(["sh", "-c", "echo hello 1>&2"])
-        assert_equal(b"hello\n", result.stderr_output)
+        assert b"hello\n" == result.stderr_output
 
-    @test
-    def output_bytes_are_decoded_if_encoding_is_set(shell):
+    @wrapper
+    def test_output_bytes_are_decoded_if_encoding_is_set(shell):
         result = shell.run(["bash", "-c", r'echo -e "\u2603"'], encoding="utf8")
-        assert_equal(_u("☃\n"), result.output)
+        assert _u("☃\n") == result.output
 
-    @test
-    def cwd_of_run_can_be_set(shell):
+    @wrapper
+    def test_cwd_of_run_can_be_set(shell):
         result = shell.run(["pwd"], cwd="/")
-        assert_equal(b"/\n", result.output)
+        assert b"/\n" == result.output
 
-    @test
-    def environment_variables_can_be_added_for_run(shell):
+    @wrapper
+    def test_environment_variables_can_be_added_for_run(shell):
         result = shell.run(["sh", "-c", "echo $NAME"], update_env={"NAME": "Bob"})
-        assert_equal(b"Bob\n", result.output)
+        assert b"Bob\n" == result.output
 
-    @test
-    def exception_is_raised_if_return_code_is_not_zero(shell):
-        assert_raises(spur.RunProcessError, lambda: shell.run(["false"]))
+    @wrapper
+    def test_exception_is_raised_if_return_code_is_not_zero(shell):
+        pytest.raises(spur.RunProcessError, lambda: shell.run(["false"]))
 
-    @test
-    def exception_has_output_from_command(shell):
+    @wrapper
+    def test_exception_has_output_from_command(shell):
         try:
             shell.run(["sh", "-c", "echo Hello world!; false"])
-            assert_true(False)
+            assert False
         except spur.RunProcessError as error:
-            assert_equal(b"Hello world!\n", error.output)
+            assert b"Hello world!\n" == error.output
 
-    @test
-    def exception_has_stderr_output_from_command(shell):
+    @wrapper
+    def test_exception_has_stderr_output_from_command(shell):
         try:
             shell.run(["sh", "-c", "echo Hello world! 1>&2; false"])
-            assert_true(False)
+            assert False
         except spur.RunProcessError as error:
-            assert_equal(b"Hello world!\n", error.stderr_output)
+            assert b"Hello world!\n" == error.stderr_output
 
-    @test
-    def exception_message_contains_return_code_and_all_output(shell):
+    @wrapper
+    def test_exception_message_contains_return_code_and_all_output(shell):
         try:
             shell.run(["sh", "-c", "echo starting; echo failed! 1>&2; exit 1"])
-            assert_true(False)
+            assert False
         except spur.RunProcessError as error:
-            assert_equal(
-                """return code: 1\noutput: b'starting\\n'\nstderr output: b'failed!\\n'""",
-                error.args[0]
-            )
+            assert (
+                """return code: 1\noutput: b'starting\\n'\nstderr output: b'failed!\\n'""" ==
+                error.args[0])
 
-    @test
-    def exception_message_contains_output_as_string_if_encoding_is_set(shell):
+    @wrapper
+    def test_exception_message_contains_output_as_string_if_encoding_is_set(shell):
         try:
             shell.run(["sh", "-c", "echo starting; echo failed! 1>&2; exit 1"], encoding="ascii")
-            assert_true(False)
+            assert False
         except spur.RunProcessError as error:
-            assert_equal(
-                """return code: 1\noutput:\nstarting\n\nstderr output:\nfailed!\n""",
-                error.args[0]
-            )
+            assert (
+                """return code: 1\noutput:\nstarting\n\nstderr output:\nfailed!\n""" ==
+                error.args[0])
 
-    @test
-    def exception_message_shows_unicode_bytes(shell):
+    @wrapper
+    def test_exception_message_shows_unicode_bytes(shell):
         try:
             shell.run(["sh", "-c", _u("echo ‽; exit 1")])
-            assert_true(False)
+            assert False
         except spur.RunProcessError as error:
-            assert_equal(
-                """return code: 1\noutput: b'\\xe2\\x80\\xbd\\n'\nstderr output: b''""",
-                error.args[0]
-            )
+            assert (
+                """return code: 1\noutput: b'\\xe2\\x80\\xbd\\n'\nstderr output: b''""" ==
+                error.args[0])
 
-    @test
-    def return_code_stored_if_errors_allowed(shell):
+    @wrapper
+    def test_return_code_stored_if_errors_allowed(shell):
         result = shell.run(["sh", "-c", "exit 14"], allow_error=True)
-        assert_equal(14, result.return_code)
+        assert 14 == result.return_code
 
-    @test
-    def can_get_result_of_spawned_process(shell):
+    @wrapper
+    def test_can_get_result_of_spawned_process(shell):
         process = shell.spawn(["echo", "hello"])
         result = process.wait_for_result()
-        assert_equal(b"hello\n", result.output)
+        assert b"hello\n" == result.output
 
-    @test
-    def calling_wait_for_result_is_idempotent(shell):
+    @wrapper
+    def test_calling_wait_for_result_is_idempotent(shell):
         process = shell.spawn(["echo", "hello"])
         process.wait_for_result()
         result = process.wait_for_result()
-        assert_equal(b"hello\n", result.output)
+        assert b"hello\n" == result.output
 
-    @test
-    def wait_for_result_raises_error_if_return_code_is_not_zero(shell):
+    @wrapper
+    def test_wait_for_result_raises_error_if_return_code_is_not_zero(shell):
         process = shell.spawn(["false"])
-        assert_raises(spur.RunProcessError, process.wait_for_result)
+        pytest.raises(spur.RunProcessError, process.wait_for_result)
 
-    @test
-    def can_write_to_stdin_of_spawned_processes(shell):
+    @wrapper
+    def test_can_write_to_stdin_of_spawned_processes(shell):
         process = shell.spawn(["sh", "-c", "read value; echo $value"])
         process.stdin_write(b"hello\n")
         result = process.wait_for_result()
-        assert_equal(b"hello\n", result.output)
+        assert b"hello\n" == result.output
 
-    @test
-    def can_tell_if_spawned_process_is_running(shell):
+    @wrapper
+    def test_can_tell_if_spawned_process_is_running(shell):
         process = shell.spawn(["sh", "-c", "echo after; read dont_care; echo after"])
-        assert_equal(True, process.is_running())
+        assert True == process.is_running()
         process.stdin_write(b"\n")
-        _wait_for_assertion(lambda: assert_equal(False, process.is_running()))
+        time.sleep(10.0)
+        assert False == process.is_running()
 
-    @test
-    def can_write_stdout_to_file_object_while_process_is_executing(shell):
+    @wrapper
+    def test_can_write_stdout_to_file_object_while_process_is_executing(shell):
         output_file = io.BytesIO()
         process = shell.spawn(
             ["sh", "-c", "echo hello; read dont_care;"],
             stdout=output_file
         )
-        _wait_for_assertion(lambda: assert_equal(b"hello\n", output_file.getvalue()))
+        time.sleep(10.0)
+        assert b"hello\n" == output_file.getvalue()
         assert process.is_running()
         process.stdin_write(b"\n")
-        assert_equal(b"hello\n", process.wait_for_result().output)
+        assert b"hello\n" == process.wait_for_result().output
 
-    @test
-    def can_write_stderr_to_file_object_while_process_is_executing(shell):
+    @wrapper
+    def test_can_write_stderr_to_file_object_while_process_is_executing(shell):
         output_file = io.BytesIO()
         process = shell.spawn(
             ["sh", "-c", "echo hello 1>&2; read dont_care;"],
             stderr=output_file
         )
-        _wait_for_assertion(lambda: assert_equal(b"hello\n", output_file.getvalue()))
+        time.sleep(10.0)
+        assert b"hello\n" == output_file.getvalue()
         assert process.is_running()
         process.stdin_write(b"\n")
-        assert_equal(b"hello\n", process.wait_for_result().stderr_output)
+        assert b"hello\n" == process.wait_for_result().stderr_output
 
-    @test
-    def when_encoding_is_set_then_stdout_is_decoded_before_writing_to_stdout_argument(shell):
+    @wrapper
+    def test_when_encoding_is_set_then_stdout_is_decoded_before_writing_to_stdout_argument(shell):
         output_file = io.StringIO()
         process = shell.spawn(
             ["bash", "-c", r'echo -e "\u2603"hello; read dont_care'],
             stdout=output_file,
             encoding="utf-8",
         )
-        _wait_for_assertion(lambda: assert_equal(_u("☃hello\n"), output_file.getvalue()))
+        time.sleep(10.0)
+        assert _u("☃hello\n") == output_file.getvalue()
         assert process.is_running()
         process.stdin_write(b"\n")
-        assert_equal(_u("☃hello\n"), process.wait_for_result().output)
+        assert _u("☃hello\n") == process.wait_for_result().output
 
-    @test
-    def can_get_process_id_of_process_if_store_pid_is_true(shell):
+    @wrapper
+    def test_can_get_process_id_of_process_if_store_pid_is_true(shell):
         process = shell.spawn(["sh", "-c", "echo $$"], store_pid=True)
         result = process.wait_for_result()
-        assert_equal(int(result.output.strip()), process.pid)
+        assert int(result.output.strip()) == process.pid
 
-    @test
-    def process_id_is_not_available_if_store_pid_is_not_set(shell):
+    @wrapper
+    def test_process_id_is_not_available_if_store_pid_is_not_set(shell):
         process = shell.spawn(["sh", "-c", "echo $$"])
         assert not hasattr(process, "pid")
 
-    @test
-    def can_send_signal_to_process_if_store_pid_is_set(shell):
+    @wrapper
+    def test_can_send_signal_to_process_if_store_pid_is_set(shell):
         process = shell.spawn(["cat"], store_pid=True)
         assert process.is_running()
         process.send_signal(signal.SIGTERM)
-        _wait_for_assertion(lambda: assert_equal(False, process.is_running()))
+        time.sleep(10.0)
+        assert False == process.is_running()
 
 
-    @test
-    def spawning_non_existent_command_raises_specific_no_such_command_exception(shell):
+    @wrapper
+    def test_spawning_non_existent_command_raises_specific_no_such_command_exception(shell):
         try:
             shell.spawn(["bin/i-am-not-a-command"])
-            # Expected exception
-            assert False
         except spur.NoSuchCommandError as error:
-            assert_equal("No such command: bin/i-am-not-a-command", error.args[0])
-            assert_equal("bin/i-am-not-a-command", error.command)
+            assert "No such command: bin/i-am-not-a-command" in error.args[0]
+            assert "bin/i-am-not-a-command" in error.command
 
 
-    @test
-    def spawning_command_that_uses_path_env_variable_asks_if_command_is_installed(shell):
+    @wrapper
+    def test_spawning_command_that_uses_path_env_variable_asks_if_command_is_installed(shell):
         try:
             shell.spawn(["i-am-not-a-command"])
-            # Expected exception
-            assert False
         except spur.NoSuchCommandError as error:
             expected_message = (
                 "Command not found: i-am-not-a-command." +
                 " Check that i-am-not-a-command is installed and on $PATH"
             )
-            assert_equal(expected_message, error.args[0])
-            assert_equal("i-am-not-a-command", error.command)
+            assert expected_message in error.args[0]
+            assert "i-am-not-a-command" in error.command
 
 
-    @test
-    def using_non_existent_cwd_does_not_raise_no_such_command_error(shell):
+    @wrapper
+    def test_using_non_existent_cwd_does_not_raise_no_such_command_error(shell):
         cwd = "/some/path/that/hopefully/doesnt/exists/ljaslkfjaslkfjas"
         try:
             shell.spawn(["echo", "1"], cwd=cwd)
-            # Expected exception
-            assert False
         except Exception as error:
             assert not isinstance(error, spur.NoSuchCommandError)
 
 
-    @test
-    def commands_are_run_without_pseudo_terminal_by_default(shell):
+    @wrapper
+    def test_commands_are_run_without_pseudo_terminal_by_default(shell):
         result = shell.run(["bash", "-c", "[ -t 0 ]"], allow_error=True)
-        assert_not_equal(0, result.return_code)
+        assert 0 != result.return_code
 
 
-    @test
-    def command_can_be_explicitly_run_with_pseudo_terminal(shell):
+    @wrapper
+    def test_command_can_be_explicitly_run_with_pseudo_terminal(shell):
         result = shell.run(["bash", "-c", "[ -t 0 ]"], allow_error=True, use_pty=True)
-        assert_equal(0, result.return_code)
+        assert 0 == result.return_code
 
 
-    @test
-    def output_is_captured_when_using_pty(shell):
+    @wrapper
+    def test_output_is_captured_when_using_pty(shell):
         result = shell.run(["echo", "-n", "hello"], use_pty=True)
-        assert_equal(b"hello", result.output)
+        assert b"hello" == result.output
 
 
-    @test
-    def stderr_is_redirected_stdout_when_using_pty(shell):
+    @wrapper
+    def test_stderr_is_redirected_stdout_when_using_pty(shell):
         result = shell.run(["sh", "-c", "echo -n hello 1>&2"], use_pty=True)
-        assert_equal(b"hello", result.output)
-        assert_equal(b"", result.stderr_output)
+        assert b"hello" == result.output
+        assert b"" == result.stderr_output
 
 
-    @test
-    def can_write_to_stdin_of_spawned_process_when_using_pty(shell):
+    @wrapper
+    def test_can_write_to_stdin_of_spawned_process_when_using_pty(shell):
         process = shell.spawn(["sh", "-c", "read value; echo $value"], use_pty=True)
         process.stdin_write(b"hello\n")
         result = process.wait_for_result()
         # Get the output twice since the pty echoes input
-        assert_equal(b"hello\r\nhello\r\n", result.output)
+        assert b"hello\r\nhello\r\n" == result.output
 
-    @test
-    def using_non_existent_cwd_raises_could_not_change_directory_error(shell):
+    @wrapper
+    def test_using_non_existent_cwd_raises_could_not_change_directory_error(shell):
         cwd = "/some/silly/path"
         try:
             shell.spawn(["echo", "1"], cwd=cwd)
-            # Expected exception
-            assert False
         except spur.CouldNotChangeDirectoryError as error:
-            assert_equal("Could not change directory to: {0}".format(cwd), error.args[0].split("\n")[0])
-            assert_equal(cwd, error.directory)
+            assert "Could not change directory to: {0}".format(cwd) == error.args[0].split("\n")[0]
+            assert cwd == error.directory
 
-    @test
-    def attempting_to_change_directory_without_permissions_raises_cannot_change_directory_error(shell):
+    @wrapper
+    def test_attempting_to_change_directory_without_permissions_raises_cannot_change_directory_error(shell):
         with shell.temporary_dir() as temp_dir:
             dir_without_execute_permissions = posixpath.join(temp_dir, "a")
             shell.run(["mkdir", dir_without_execute_permissions])
             shell.run(["chmod", "-x", dir_without_execute_permissions])
             try:
                 shell.spawn(["true"], cwd=dir_without_execute_permissions)
-                # Expected exception
-                assert False
             except spur.CouldNotChangeDirectoryError as error:
-                assert_equal(dir_without_execute_permissions, error.directory)
+                assert dir_without_execute_permissions == error.directory
 
-    @test
-    def using_non_existent_cwd_and_command_raises_could_not_change_directory_error(shell):
+    @wrapper
+    def test_using_non_existent_cwd_and_command_raises_could_not_change_directory_error(shell):
         try:
             shell.spawn(["bin/i-am-not-a-command"], cwd="/some/silly/path")
-            # Expected exception
-            assert False
         except spur.CouldNotChangeDirectoryError as error:
-            assert_equal("/some/silly/path", error.directory)
+            assert "/some/silly/path" == error.directory
 
-    @test
-    def using_non_existent_command_and_correct_cwd_raises_no_such_command_exception(shell):
+    @wrapper
+    def test_using_non_existent_command_and_correct_cwd_raises_no_such_command_exception(shell):
         try:
             shell.spawn(["bin/i-am-not-a-command"], cwd="/bin")
-            # Expected exception
-            assert False
         except spur.NoSuchCommandError as error:
-            assert_equal("bin/i-am-not-a-command", error.command)
+            assert "bin/i-am-not-a-command" in error.command
 
-    @test
-    def can_find_command_in_cwd(shell):
+    @wrapper
+    def test_can_find_command_in_cwd(shell):
         # TODO: the behaviour in subprocess seems to be inconsistent between
         # both Python versions and platforms (Windows vs Unix)
         # See:
         # * https://bugs.python.org/issue15533
         # * https://bugs.python.org/issue20927
         result = shell.run(["./ls"], cwd="/bin")
-        assert_equal(result.return_code, 0)
+        assert result.return_code == 0
 
-    @istest
     def shell_can_be_closed_using_close_method(self):
         shell = self.create_shell()
         try:
             result = shell.run(["echo", "hello"])
-            assert_equal(b"hello\n", result.output)
+            assert b"hello\n" == result.output
         finally:
             shell.close()
 
diff --git a/tests/ssh_tests.py b/tests/test_ssh.py
similarity index 51%
rename from tests/ssh_tests.py
rename to tests/test_ssh.py
index a239434..93a97c1 100644
--- a/tests/ssh_tests.py
+++ b/tests/test_ssh.py
@@ -3,42 +3,43 @@
 import io
 import socket
 
-from nose.tools import istest, assert_raises, assert_equal
 from paramiko.util import retry_on_signal
 
 import spur
 import spur.ssh
 from .testing import create_ssh_shell, HOSTNAME, PORT, PASSWORD, USERNAME
-from .process_test_set import ProcessTestSet
-from .open_test_set import OpenTestSet
+from .test_process_set import ProcessTestSet
+from .test_open_set import OpenTestSet
+
+import pytest
 
 
 class SshTestMixin(object):
     def create_shell(self):
         return create_ssh_shell()
-    
 
-@istest
-class SshOpenTests(OpenTestSet, SshTestMixin):
+
+
+class TestSshOpenTests(OpenTestSet, SshTestMixin):
     pass
 
 
-@istest
-class SshProcessTests(ProcessTestSet, SshTestMixin):
+
+class TestSshProcessTests(ProcessTestSet, SshTestMixin):
     pass
 
 
-@istest
-def attempting_to_connect_to_wrong_port_raises_connection_error():
+
+def test_attempting_to_connect_to_wrong_port_raises_connection_error():
     def try_connection():
         shell = _create_shell_with_wrong_port()
         shell.run(["echo", "hello"])
-        
-    assert_raises(spur.ssh.ConnectionError, try_connection)
+
+    pytest.raises(spur.ssh.ConnectionError, try_connection)
 
 
-@istest
-def connection_error_contains_original_error():
+
+def test_connection_error_contains_original_error():
     try:
         shell = _create_shell_with_wrong_port()
         shell.run(["true"])
@@ -48,8 +49,8 @@ def connection_error_contains_original_error():
         assert isinstance(error.original_error, IOError)
 
 
-@istest
-def connection_error_contains_traceback_for_original_error():
+
+def test_connection_error_contains_traceback_for_original_error():
     try:
         shell = _create_shell_with_wrong_port()
         shell.run(["true"])
@@ -59,40 +60,40 @@ def connection_error_contains_traceback_for_original_error():
         assert "Traceback (most recent call last):" in error.original_traceback
 
 
-@istest
-def missing_host_key_set_to_accept_allows_connection_with_missing_host_key():
+
+def test_missing_host_key_set_to_accept_allows_connection_with_missing_host_key():
     with create_ssh_shell(missing_host_key=spur.ssh.MissingHostKey.accept) as shell:
         shell.run(["true"])
 
 
-@istest
-def missing_host_key_set_to_warn_allows_connection_with_missing_host_key():
+
+def test_missing_host_key_set_to_warn_allows_connection_with_missing_host_key():
     with create_ssh_shell(missing_host_key=spur.ssh.MissingHostKey.warn) as shell:
         shell.run(["true"])
 
 
-@istest
-def missing_host_key_set_to_raise_error_raises_error_when_missing_host_key():
+
+def test_missing_host_key_set_to_raise_error_raises_error_when_missing_host_key():
     with create_ssh_shell(missing_host_key=spur.ssh.MissingHostKey.raise_error) as shell:
-        assert_raises(spur.ssh.ConnectionError, lambda: shell.run(["true"]))
-        
+        pytest.raises(spur.ssh.ConnectionError, lambda: shell.run(["true"]))
 
-@istest
-def trying_to_use_ssh_shell_after_exit_results_in_error():
+
+
+def test_trying_to_use_ssh_shell_after_exit_results_in_error():
     with create_ssh_shell() as shell:
         pass
-        
-    assert_raises(Exception, lambda: shell.run(["true"]))
+
+    pytest.raises(Exception, lambda: shell.run(["true"]))
 
 
-@istest
-def an_open_socket_can_be_used_for_ssh_connection_with_sock_argument():
+
+def test_an_open_socket_can_be_used_for_ssh_connection_with_sock_argument():
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     retry_on_signal(lambda: sock.connect((HOSTNAME, PORT)))
 
     with _create_shell_with_wrong_port(sock=sock) as shell:
         result = shell.run(["echo", "hello"])
-        assert_equal(b"hello\n", result.output)
+        assert b"hello\n" == result.output
 
 
 def _create_shell_with_wrong_port(**kwargs):
@@ -109,84 +110,84 @@ def _create_shell_with_wrong_port(**kwargs):
 class MinimalSshTestMixin(object):
     def create_shell(self):
         return create_ssh_shell(shell_type=spur.ssh.ShellTypes.minimal)
-    
 
-@istest
-class MinimalSshOpenTests(OpenTestSet, MinimalSshTestMixin):
+
+
+class TestMinimalSshOpenTests(OpenTestSet, MinimalSshTestMixin):
     pass
 
 
-@istest
-class MinimalSshProcessTests(ProcessTestSet, MinimalSshTestMixin):
-    spawning_command_that_uses_path_env_variable_asks_if_command_is_installed = None
-    spawning_non_existent_command_raises_specific_no_such_command_exception = None
-    
-    can_get_process_id_of_process_if_store_pid_is_true = None
-    can_send_signal_to_process_if_store_pid_is_set = None
+
+class TestMinimalSshProcessTests(ProcessTestSet, MinimalSshTestMixin):
+    test_spawning_command_that_uses_path_env_variable_asks_if_command_is_installed = None
+    test_spawning_non_existent_command_raises_specific_no_such_command_exception = None
+
+    test_can_get_process_id_of_process_if_store_pid_is_true = None
+    test_can_send_signal_to_process_if_store_pid_is_set = None
 
     # cwd is not supported when using a minimal shell
-    using_non_existent_cwd_raises_could_not_change_directory_error = None
-    attempting_to_change_directory_without_permissions_raises_cannot_change_directory_error = None
-    using_non_existent_cwd_and_command_raises_could_not_change_directory_error = None
-    using_non_existent_command_and_correct_cwd_raises_no_such_command_exception = None
-    can_find_command_in_cwd = None
-    
-    @istest
-    def cannot_store_pid(self):
+    test_using_non_existent_cwd_raises_could_not_change_directory_error = None
+    test_attempting_to_change_directory_without_permissions_raises_cannot_change_directory_error = None
+    test_using_non_existent_cwd_and_command_raises_could_not_change_directory_error = None
+    test_using_non_existent_command_and_correct_cwd_raises_no_such_command_exception = None
+    test_can_find_command_in_cwd = None
+
+
+    def test_cannot_store_pid(self):
         self._assert_unsupported_feature(store_pid=True)
-    
-    cwd_of_run_can_be_set = None
-    
-    @istest
-    def cannot_set_cwd(self):
+
+    test_cwd_of_run_can_be_set = None
+
+
+    def test_cannot_set_cwd(self):
         self._assert_unsupported_feature(cwd="/")
-    
-    environment_variables_can_be_added_for_run = None
-    
-    @istest
-    def update_env_can_be_empty(self):
+
+    test_environment_variables_can_be_added_for_run = None
+
+
+    def test_update_env_can_be_empty(self):
         self._assert_supported_feature(update_env={})
-        
-    @istest
-    def cannot_update_env(self):
+
+
+    def test_cannot_update_env(self):
         self._assert_unsupported_feature(update_env={"x": "one"})
-        
-    @istest
-    def cannot_set_new_process_group(self):
+
+
+    def test_cannot_set_new_process_group(self):
         self._assert_unsupported_feature(new_process_group=True)
-    
-    
+
+
     def _assert_supported_feature(self, **kwargs):
         with self.create_shell() as shell:
             result = shell.run(["echo", "hello"], **kwargs)
-        
-        assert_equal(b"hello\n", result.output)
-    
-    
+
+        assert b"hello\n" == result.output
+
+
     def _assert_unsupported_feature(self, **kwargs):
         name, = kwargs.keys()
-        
+
         try:
             with self.create_shell() as shell:
                 shell.run(["echo", "hello"], **kwargs)
             assert False, "Expected error"
         except spur.ssh.UnsupportedArgumentError as error:
-            assert_equal("'{0}' is not supported when using a minimal shell".format(name), str(error))
+            assert "'{0}' is not supported when using a minimal shell".format(name) in str(error)
+
 
 
 
-@istest
 class ReadInitializationLineTests(object):
-    @istest
-    def reading_initialization_line_returns_int_from_line_of_file(self):
-        assert_equal(42, spur.ssh._read_int_initialization_line(io.StringIO("42\n")))
-        
-    @istest
-    def blank_lines_are_skipped(self):
-        assert_equal(42, spur.ssh._read_int_initialization_line(io.StringIO("\n \n\t\t\n42\n")))
-        
-    @istest
-    def error_if_non_blank_line_is_not_integer(self):
+
+    def test_reading_initialization_line_returns_int_from_line_of_file(self):
+        assert 42 == spur.ssh._read_int_initialization_line(io.StringIO("42\n"))
+
+
+    def test_blank_lines_are_skipped(self):
+        assert 42 == spur.ssh._read_int_initialization_line(io.StringIO("\n \n\t\t\n42\n"))
+
+
+    def test_error_if_non_blank_line_is_not_integer(self):
         try:
             spur.ssh._read_int_initialization_line(io.StringIO("x\n"))
             assert False, "Expected error"
