Simplify tests by replacing output capture with asserts where possible

The C++ part of the test code is modified to achieve this. As a result,
this kind of test:

```python
with capture:
    kw_func1(5, y=10)
assert capture == "kw_func(x=5, y=10)"
```

can be replaced with a simple:

`assert kw_func1(5, y=10) == "x=5, y=10"`
diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp
index 80a0d0e..270ff5c 100644
--- a/tests/test_callbacks.cpp
+++ b/tests/test_callbacks.cpp
@@ -12,18 +12,16 @@
 #include <pybind11/functional.h>
 
 
-bool test_callback1(py::object func) {
-    func();
-    return false;
+py::object test_callback1(py::object func) {
+    return func();
 }
 
-int test_callback2(py::object func) {
-    py::object result = func("Hello", 'x', true, 5);
-    return result.cast<int>();
+py::tuple test_callback2(py::object func) {
+    return func("Hello", 'x', true, 5);
 }
 
-void test_callback3(const std::function<int(int)> &func) {
-    cout << "func(43) = " << func(43)<< std::endl;
+std::string test_callback3(const std::function<int(int)> &func) {
+    return "func(43) = " + std::to_string(func(43));
 }
 
 std::function<int(int)> test_callback4() {
@@ -37,27 +35,24 @@
 
 int dummy_function(int i) { return i + 1; }
 int dummy_function2(int i, int j) { return i + j; }
-std::function<int(int)> roundtrip(std::function<int(int)> f) { 
-    if (!f)
-        std::cout << "roundtrip (got None).." << std::endl;
-    else
-        std::cout << "roundtrip.." << std::endl;
+std::function<int(int)> roundtrip(std::function<int(int)> f, bool expect_none = false) {
+    if (expect_none && f) {
+        throw std::runtime_error("Expected None to be converted to empty std::function");
+    }
     return f;
 }
 
-void test_dummy_function(const std::function<int(int)> &f) {
+std::string test_dummy_function(const std::function<int(int)> &f) {
     using fn_type = int (*)(int);
     auto result = f.target<fn_type>();
     if (!result) {
-        std::cout << "could not convert to a function pointer." << std::endl;
         auto r = f(1);
-        std::cout << "eval(1) = " << r << std::endl;
+        return "can't convert to function pointer: eval(1) = " + std::to_string(r);
     } else if (*result == dummy_function) {
-        std::cout << "argument matches dummy_function" << std::endl;
         auto r = (*result)(1);
-        std::cout << "eval(1) = " << r << std::endl;
+        return "matches dummy_function: eval(1) = " + std::to_string(r);
     } else {
-        std::cout << "argument does NOT match dummy_function. This should never happen!" << std::endl;
+        return "argument does NOT match dummy_function. This should never happen!";
     }
 }
 
@@ -96,7 +91,7 @@
     /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
     m.def("dummy_function", &dummy_function);
     m.def("dummy_function2", &dummy_function2);
-    m.def("roundtrip", &roundtrip);
+    m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false);
     m.def("test_dummy_function", &test_dummy_function);
     // Export the payload constructor statistics for testing purposes:
     m.def("payload_cstats", &ConstructorStats::get<Payload>);
diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py
index 3f70e87..83bc016 100644
--- a/tests/test_callbacks.py
+++ b/tests/test_callbacks.py
@@ -1,70 +1,51 @@
 import pytest
 
 
-def test_inheritance(capture, msg):
-    from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_print
+def test_inheritance(msg):
+    from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species
 
     roger = Rabbit('Rabbit')
     assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
-    with capture:
-        pet_print(roger)
-    assert capture == "Rabbit is a parrot"
+    assert pet_name_species(roger) == "Rabbit is a parrot"
 
     polly = Pet('Polly', 'parrot')
     assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
-    with capture:
-        pet_print(polly)
-    assert capture == "Polly is a parrot"
+    assert pet_name_species(polly) == "Polly is a parrot"
 
     molly = Dog('Molly')
     assert molly.name() + " is a " + molly.species() == "Molly is a dog"
-    with capture:
-        pet_print(molly)
-    assert capture == "Molly is a dog"
+    assert pet_name_species(molly) == "Molly is a dog"
 
-    with capture:
-        dog_bark(molly)
-    assert capture == "Woof!"
+    assert dog_bark(molly) == "Woof!"
 
     with pytest.raises(TypeError) as excinfo:
         dog_bark(polly)
     assert msg(excinfo.value) == """
         Incompatible function arguments. The following argument types are supported:
-            1. (arg0: m.Dog) -> None
+            1. (arg0: m.Dog) -> str
             Invoked with: <m.Pet object at 0>
     """
 
 
-def test_callbacks(capture):
+def test_callbacks():
     from functools import partial
     from pybind11_tests import (test_callback1, test_callback2, test_callback3,
                                 test_callback4, test_callback5)
 
     def func1():
-        print('Callback function 1 called!')
+        return "func1"
 
     def func2(a, b, c, d):
-        print('Callback function 2 called : {}, {}, {}, {}'.format(a, b, c, d))
-        return d
+        return "func2", a, b, c, d
 
     def func3(a):
-        print('Callback function 3 called : {}'.format(a))
+        return "func3({})".format(a)
 
-    with capture:
-        assert test_callback1(func1) is False
-    assert capture == "Callback function 1 called!"
-    with capture:
-        assert test_callback2(func2) == 5
-    assert capture == "Callback function 2 called : Hello, x, True, 5"
-    with capture:
-        assert test_callback1(partial(func2, "Hello", "from", "partial", "object")) is False
-    assert capture == "Callback function 2 called : Hello, from, partial, object"
-    with capture:
-        assert test_callback1(partial(func3, "Partial object with one argument")) is False
-    assert capture == "Callback function 3 called : Partial object with one argument"
-    with capture:
-        test_callback3(lambda i: i + 1)
-    assert capture == "func(43) = 44"
+    assert test_callback1(func1) == "func1"
+    assert test_callback2(func2) == ("func2", "Hello", "x", True, 5)
+    assert test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
+    assert test_callback1(partial(func3, "partial")) == "func3(partial)"
+    assert test_callback3(lambda i: i + 1) == "func(43) = 44"
 
     f = test_callback4()
     assert f(43) == 44
@@ -82,49 +63,27 @@
     assert cstats.move_constructions >= 1
 
 
-def test_cpp_function_roundtrip(capture):
+def test_cpp_function_roundtrip():
     """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
     from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip
 
-    with capture:
-        test_dummy_function(dummy_function)
-    assert capture == """
-        argument matches dummy_function
-        eval(1) = 2
-    """
-    with capture:
-        test_dummy_function(roundtrip(dummy_function))
-    assert capture == """
-        roundtrip..
-        argument matches dummy_function
-        eval(1) = 2
-    """
-    with capture:
-        assert roundtrip(None) is None
-    assert capture == "roundtrip (got None).."
-    with capture:
-        test_dummy_function(lambda x: x + 2)
-    assert capture == """
-        could not convert to a function pointer.
-        eval(1) = 3
-    """
+    assert test_dummy_function(dummy_function) == "matches dummy_function: eval(1) = 2"
+    assert test_dummy_function(roundtrip(dummy_function)) == "matches dummy_function: eval(1) = 2"
+    assert roundtrip(None, expect_none=True) is None
+    assert test_dummy_function(lambda x: x + 2) == "can't convert to function pointer: eval(1) = 3"
 
-    with capture:
-        with pytest.raises(TypeError) as excinfo:
-            test_dummy_function(dummy_function2)
-        assert "Incompatible function arguments" in str(excinfo.value)
-    assert capture == "could not convert to a function pointer."
+    with pytest.raises(TypeError) as excinfo:
+        test_dummy_function(dummy_function2)
+    assert "Incompatible function arguments" in str(excinfo.value)
 
-    with capture:
-        with pytest.raises(TypeError) as excinfo:
-            test_dummy_function(lambda x, y: x + y)
-        assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
-                                                     "takes exactly 2 arguments"))
-    assert capture == "could not convert to a function pointer."
+    with pytest.raises(TypeError) as excinfo:
+        test_dummy_function(lambda x, y: x + y)
+    assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
+                                                 "takes exactly 2 arguments"))
 
 
 def test_function_signatures(doc):
     from pybind11_tests import test_callback3, test_callback4
 
-    assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> None"
+    assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
     assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]"
diff --git a/tests/test_constants_and_functions.cpp b/tests/test_constants_and_functions.cpp
index 1977a0a..077fa78 100644
--- a/tests/test_constants_and_functions.cpp
+++ b/tests/test_constants_and_functions.cpp
@@ -27,27 +27,24 @@
     };
 
     static EMode test_function(EMode mode) {
-        std::cout << "ExampleWithEnum::test_function(enum=" << mode << ")" << std::endl;
         return mode;
     }
 };
 
-bool test_function1() {
-    std::cout << "test_function()" << std::endl;
-    return false;
+std::string test_function1() {
+    return "test_function()";
 }
 
-void test_function2(EMyEnumeration k) {
-    std::cout << "test_function(enum=" << k << ")" << std::endl;
+std::string test_function2(EMyEnumeration k) {
+    return "test_function(enum=" + std::to_string(k) + ")";
 }
 
-float test_function3(int i) {
-    std::cout << "test_function(" << i << ")" << std::endl;
-    return (float) i / 2.f;
+std::string test_function3(int i) {
+    return "test_function(" + std::to_string(i) + ")";
 }
 
-void test_ecenum(ECMyEnum z) {
-    std::cout << "test_ecenum(ECMyEnum::" << (z == ECMyEnum::Two ? "Two" : "Three") << ")" << std::endl;
+std::string test_ecenum(ECMyEnum z) {
+    return "test_ecenum(ECMyEnum::" + std::string(z == ECMyEnum::Two ? "Two" : "Three") + ")";
 }
 
 py::bytes return_bytes() {
@@ -55,10 +52,14 @@
     return std::string(data, 4);
 }
 
-void print_bytes(py::bytes bytes) {
-    std::string value = (std::string) bytes;
-    for (size_t i = 0; i < value.length(); ++i)
-        std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl;
+std::string print_bytes(py::bytes bytes) {
+    std::string ret = "bytes[";
+    const auto value = static_cast<std::string>(bytes);
+    for (size_t i = 0; i < value.length(); ++i) {
+        ret += std::to_string(static_cast<int>(value[i])) + " ";
+    }
+    ret.back() = ']';
+    return ret;
 }
 
 void init_ex_constants_and_functions(py::module &m) {
diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py
index 119965b..8295ef6 100644
--- a/tests/test_constants_and_functions.py
+++ b/tests/test_constants_and_functions.py
@@ -7,20 +7,13 @@
     assert some_constant == 14
 
 
-def test_function_overloading(capture):
+def test_function_overloading():
     from pybind11_tests import EMyEnumeration, test_function
 
-    with capture:
-        assert test_function() is False
-        assert test_function(7) == 3.5
-        assert test_function(EMyEnumeration.EFirstEntry) is None
-        assert test_function(EMyEnumeration.ESecondEntry) is None
-    assert capture == """
-        test_function()
-        test_function(7)
-        test_function(enum=1)
-        test_function(enum=2)
-    """
+    assert test_function() == "test_function()"
+    assert test_function(7) == "test_function(7)"
+    assert test_function(EMyEnumeration.EFirstEntry) == "test_function(enum=1)"
+    assert test_function(EMyEnumeration.ESecondEntry) == "test_function(enum=2)"
 
 
 def test_unscoped_enum():
@@ -39,16 +32,12 @@
     assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry"
 
 
-def test_scoped_enum(capture):
+def test_scoped_enum():
     from pybind11_tests import ECMyEnum, test_ecenum
 
-    with capture:
-        test_ecenum(ECMyEnum.Three)
-    assert capture == "test_ecenum(ECMyEnum::Three)"
+    assert test_ecenum(ECMyEnum.Three) == "test_ecenum(ECMyEnum::Three)"
     z = ECMyEnum.Two
-    with capture:
-        test_ecenum(z)
-    assert capture == "test_ecenum(ECMyEnum::Two)"
+    assert test_ecenum(z) == "test_ecenum(ECMyEnum::Two)"
 
     # expected TypeError exceptions for scoped enum ==/!= int comparisons
     with pytest.raises(TypeError):
@@ -57,7 +46,7 @@
         assert z != 3
 
 
-def test_implicit_conversion(capture):
+def test_implicit_conversion():
     from pybind11_tests import ExampleWithEnum
 
     assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode"
@@ -67,64 +56,29 @@
     first = ExampleWithEnum.EFirstMode
     second = ExampleWithEnum.ESecondMode
 
-    with capture:
-        f(first)
-    assert capture == "ExampleWithEnum::test_function(enum=1)"
+    assert f(first) == 1
 
-    with capture:
-        assert f(first) == f(first)
-        assert not f(first) != f(first)
+    assert f(first) == f(first)
+    assert not f(first) != f(first)
 
-        assert f(first) != f(second)
-        assert not f(first) == f(second)
+    assert f(first) != f(second)
+    assert not f(first) == f(second)
 
-        assert f(first) == int(f(first))
-        assert not f(first) != int(f(first))
+    assert f(first) == int(f(first))
+    assert not f(first) != int(f(first))
 
-        assert f(first) != int(f(second))
-        assert not f(first) == int(f(second))
-    assert capture == """
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=2)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=2)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=2)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=2)
-    """
+    assert f(first) != int(f(second))
+    assert not f(first) == int(f(second))
 
-    with capture:
-        # noinspection PyDictCreation
-        x = {f(first): 1, f(second): 2}
-        x[f(first)] = 3
-        x[f(second)] = 4
-    assert capture == """
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=2)
-        ExampleWithEnum::test_function(enum=1)
-        ExampleWithEnum::test_function(enum=2)
-    """
+    # noinspection PyDictCreation
+    x = {f(first): 1, f(second): 2}
+    x[f(first)] = 3
+    x[f(second)] = 4
     # Hashing test
     assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}"
 
 
-def test_bytes(capture):
+def test_bytes():
     from pybind11_tests import return_bytes, print_bytes
 
-    with capture:
-        print_bytes(return_bytes())
-    assert capture == """
-        bytes[0]=1
-        bytes[1]=0
-        bytes[2]=2
-        bytes[3]=0
-    """
+    assert print_bytes(return_bytes()) == "bytes[1 0 2 0]"
diff --git a/tests/test_inheritance.cpp b/tests/test_inheritance.cpp
index b70ea77..2997cce 100644
--- a/tests/test_inheritance.cpp
+++ b/tests/test_inheritance.cpp
@@ -23,7 +23,7 @@
 class Dog : public Pet {
 public:
     Dog(const std::string &name) : Pet(name, "dog") {}
-    void bark() const { std::cout << "Woof!" << std::endl; }
+    std::string bark() const { return "Woof!"; }
 };
 
 class Rabbit : public Pet {
@@ -31,12 +31,12 @@
     Rabbit(const std::string &name) : Pet(name, "parrot") {}
 };
 
-void pet_print(const Pet &pet) {
-    std::cout << pet.name() + " is a " + pet.species() << std::endl;
+std::string pet_name_species(const Pet &pet) {
+    return pet.name() + " is a " + pet.species();
 }
 
-void dog_bark(const Dog &dog) {
-    dog.bark();
+std::string dog_bark(const Dog &dog) {
+    return dog.bark();
 }
 
 
@@ -59,7 +59,7 @@
     py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
         .def(py::init<std::string>());
 
-    m.def("pet_print", pet_print);
+    m.def("pet_name_species", pet_name_species);
     m.def("dog_bark", dog_bark);
 
     py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp
index 085dff9..a0d1fd5 100644
--- a/tests/test_issues.cpp
+++ b/tests/test_issues.cpp
@@ -34,19 +34,20 @@
 #endif
 
     // #137: const char* isn't handled properly
-    m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; });
+    m2.def("print_cchar", [](const char *s) { return std::string(s); });
 
     // #150: char bindings broken
-    m2.def("print_char", [](char c) { std::cout << c << std::endl; });
+    m2.def("print_char", [](char c) { return std::string(1, c); });
 
     // #159: virtual function dispatch has problems with similar-named functions
-    struct Base { virtual void dispatch(void) const {
+    struct Base { virtual std::string dispatch() const {
         /* for some reason MSVC2015 can't compile this if the function is pure virtual */
+        return {};
     }; };
 
     struct DispatchIssue : Base {
-        virtual void dispatch(void) const {
-            PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */);
+        virtual std::string dispatch() const {
+            PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
         }
     };
 
@@ -54,7 +55,7 @@
         .def(py::init<>())
         .def("dispatch", &Base::dispatch);
 
-    m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); });
+    m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
 
     struct Placeholder { int i; Placeholder(int i) : i(i) { } };
 
@@ -171,7 +172,7 @@
         .def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
     py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
     py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
-    m2.def("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; });
-    m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; });
-    m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; });
+    m2.def("get_NestA", [](const NestA &a) { return a.value; });
+    m2.def("get_NestB", [](const NestB &b) { return b.value; });
+    m2.def("get_NestC", [](const NestC &c) { return c.value; });
 }
diff --git a/tests/test_issues.py b/tests/test_issues.py
index 0ab2e36..f768139 100644
--- a/tests/test_issues.py
+++ b/tests/test_issues.py
@@ -2,24 +2,22 @@
 import gc
 
 
-def test_regressions(capture):
+def test_regressions():
     from pybind11_tests.issues import print_cchar, print_char
 
-    with capture:
-        print_cchar("const char *")  # #137: const char* isn't handled properly
-    assert capture == "const char *"
-    with capture:
-        print_char("c")  # #150: char bindings broken
-    assert capture == "c"
+    # #137: const char* isn't handled properly
+    assert print_cchar("const char *") == "const char *"
+    # #150: char bindings broken
+    assert print_char("c") == "c"
 
 
-def test_dispatch_issue(capture, msg):
+def test_dispatch_issue(msg):
     """#159: virtual function dispatch has problems with similar-named functions"""
     from pybind11_tests.issues import DispatchIssue, dispatch_issue_go
 
     class PyClass1(DispatchIssue):
         def dispatch(self):
-            print("Yay..")
+            return "Yay.."
 
     class PyClass2(DispatchIssue):
         def dispatch(self):
@@ -28,12 +26,10 @@
             assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
 
             p = PyClass1()
-            dispatch_issue_go(p)
+            return dispatch_issue_go(p)
 
     b = PyClass2()
-    with capture:
-        dispatch_issue_go(b)
-    assert capture == "Yay.."
+    assert dispatch_issue_go(b) == "Yay.."
 
 
 def test_reference_wrapper():
@@ -127,36 +123,26 @@
     """
 
 
-def test_nested(capture):
+def test_nested():
     """ #328: first member in a class can't be used in operators"""
-    from pybind11_tests.issues import NestA, NestB, NestC, print_NestA, print_NestB, print_NestC
+    from pybind11_tests.issues import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
 
     a = NestA()
     b = NestB()
     c = NestC()
 
     a += 10
+    assert get_NestA(a) == 13
     b.a += 100
+    assert get_NestA(b.a) == 103
     c.b.a += 1000
+    assert get_NestA(c.b.a) == 1003
     b -= 1
+    assert get_NestB(b) == 3
     c.b -= 3
+    assert get_NestB(c.b) == 1
     c *= 7
-
-    with capture:
-        print_NestA(a)
-        print_NestA(b.a)
-        print_NestA(c.b.a)
-        print_NestB(b)
-        print_NestB(c.b)
-        print_NestC(c)
-    assert capture == """
-        13
-        103
-        1003
-        3
-        1
-        35
-    """
+    assert get_NestC(c) == 35
 
     abase = a.as_base()
     assert abase.value == -2
diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp
index 2816246..3fefc79 100644
--- a/tests/test_kwargs_and_defaults.cpp
+++ b/tests/test_kwargs_and_defaults.cpp
@@ -10,13 +10,14 @@
 #include "pybind11_tests.h"
 #include <pybind11/stl.h>
 
-void kw_func(int x, int y) { std::cout << "kw_func(x=" << x << ", y=" << y << ")" << std::endl; }
+std::string kw_func(int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }
 
-void kw_func4(const std::vector<int> &entries) {
-    std::cout << "kw_func4: ";
+std::string kw_func4(const std::vector<int> &entries) {
+    std::string ret = "{";
     for (int i : entries)
-        std::cout << i << " ";
-    std::cout << endl;
+        ret += std::to_string(i) + " ";
+    ret.back() = '}';
+    return ret;
 }
 
 py::object call_kw_func(py::function f) {
diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py
index 0d785a4..735722d 100644
--- a/tests/test_kwargs_and_defaults.py
+++ b/tests/test_kwargs_and_defaults.py
@@ -5,77 +5,51 @@
 
 
 def test_function_signatures(doc):
-    assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> None"
-    assert doc(kw_func1) == "kw_func1(x: int, y: int) -> None"
-    assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> None"
+    assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
+    assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str"
+    assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str"
     assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None"
-    assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> None"
-    assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> None"
-    assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> None"
+    assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str"
+    assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str"
+    assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str"
     assert doc(args_function) == "args_function(*args) -> None"
     assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> None"
     assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None"
     assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None"
 
 
-def test_named_arguments(capture, msg):
-    with capture:
-        kw_func1(5, 10)
-    assert capture == "kw_func(x=5, y=10)"
-    with capture:
-        kw_func1(5, y=10)
-    assert capture == "kw_func(x=5, y=10)"
-    with capture:
-        kw_func1(y=10, x=5)
-    assert capture == "kw_func(x=5, y=10)"
+def test_named_arguments(msg):
+    assert kw_func0(5, 10) == "x=5, y=10"
 
-    with capture:
-        kw_func2()
-    assert capture == "kw_func(x=100, y=200)"
-    with capture:
-        kw_func2(5)
-    assert capture == "kw_func(x=5, y=200)"
-    with capture:
-        kw_func2(x=5)
-    assert capture == "kw_func(x=5, y=200)"
-    with capture:
-        kw_func2(y=10)
-    assert capture == "kw_func(x=100, y=10)"
-    with capture:
-        kw_func2(5, 10)
-    assert capture == "kw_func(x=5, y=10)"
-    with capture:
-        kw_func2(x=5, y=10)
-    assert capture == "kw_func(x=5, y=10)"
+    assert kw_func1(5, 10) == "x=5, y=10"
+    assert kw_func1(5, y=10) == "x=5, y=10"
+    assert kw_func1(y=10, x=5) == "x=5, y=10"
+
+    assert kw_func2() == "x=100, y=200"
+    assert kw_func2(5) == "x=5, y=200"
+    assert kw_func2(x=5) == "x=5, y=200"
+    assert kw_func2(y=10) == "x=100, y=10"
+    assert kw_func2(5, 10) == "x=5, y=10"
+    assert kw_func2(x=5, y=10) == "x=5, y=10"
 
     with pytest.raises(TypeError) as excinfo:
         # noinspection PyArgumentList
         kw_func2(x=5, y=10, z=12)
     assert msg(excinfo.value) == """
         Incompatible function arguments. The following argument types are supported:
-            1. (x: int=100, y: int=200) -> None
+            1. (x: int=100, y: int=200) -> str
             Invoked with:
     """
 
-    with capture:
-        kw_func4()
-    assert capture == "kw_func4: 13 17"
-    with capture:
-        kw_func4(myList=[1, 2, 3])
-    assert capture == "kw_func4: 1 2 3"
+    assert kw_func4() == "{13 17}"
+    assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
 
-    with capture:
-        kw_func_udl(x=5, y=10)
-    assert capture == "kw_func(x=5, y=10)"
-    with capture:
-        kw_func_udl_z(x=5)
-    assert capture == "kw_func(x=5, y=0)"
+    assert kw_func_udl(x=5, y=10) == "x=5, y=10"
+    assert kw_func_udl_z(x=5) == "x=5, y=0"
 
 
 def test_arg_and_kwargs(capture):
-    with capture:
-        call_kw_func(kw_func2)
-    assert capture == "kw_func(x=1234, y=5678)"
+    assert call_kw_func(kw_func2) == "x=1234, y=5678"
     with capture:
         args_function('arg1_value', 'arg2_value', 3)
     assert capture.unordered == """
diff --git a/tests/test_modules.cpp b/tests/test_modules.cpp
index 3d96df6..b77dacc 100644
--- a/tests/test_modules.cpp
+++ b/tests/test_modules.cpp
@@ -11,8 +11,8 @@
 #include "pybind11_tests.h"
 #include "constructor_stats.h"
 
-void submodule_func() {
-    std::cout << "submodule_func()" << std::endl;
+std::string submodule_func() {
+    return "submodule_func()";
 }
 
 class A {
diff --git a/tests/test_modules.py b/tests/test_modules.py
index 3deb02e..fe72f19 100644
--- a/tests/test_modules.py
+++ b/tests/test_modules.py
@@ -1,14 +1,12 @@
 
-def test_nested_modules(capture):
+def test_nested_modules():
     import pybind11_tests
     from pybind11_tests.submodule import submodule_func
 
     assert pybind11_tests.__name__ == "pybind11_tests"
     assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule"
 
-    with capture:
-        submodule_func()
-    assert capture == "submodule_func()"
+    assert submodule_func() == "submodule_func()"
 
 
 def test_reference_internal():
diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp
index 9afd342..b4266d0 100644
--- a/tests/test_numpy_dtypes.cpp
+++ b/tests/test_numpy_dtypes.cpp
@@ -8,7 +8,6 @@
 */
 
 #include "pybind11_tests.h"
-
 #include <pybind11/numpy.h>
 
 #ifdef __GNUC__
@@ -139,29 +138,48 @@
 }
 
 template <typename S>
-void print_recarray(py::array_t<S, 0> arr) {
-    auto req = arr.request();
-    auto ptr = static_cast<S*>(req.ptr);
-    for (size_t i = 0; i < req.size; i++)
-        std::cout << ptr[i] << std::endl;
+py::list print_recarray(py::array_t<S, 0> arr) {
+    const auto req = arr.request();
+    const auto ptr = static_cast<S*>(req.ptr);
+    auto l = py::list();
+    for (size_t i = 0; i < req.size; i++) {
+        std::stringstream ss;
+        ss << ptr[i];
+        l.append(py::str(ss.str()));
+    }
+    return l;
 }
 
-void print_format_descriptors() {
-    std::cout << py::format_descriptor<SimpleStruct>::format() << std::endl;
-    std::cout << py::format_descriptor<PackedStruct>::format() << std::endl;
-    std::cout << py::format_descriptor<NestedStruct>::format() << std::endl;
-    std::cout << py::format_descriptor<PartialStruct>::format() << std::endl;
-    std::cout << py::format_descriptor<PartialNestedStruct>::format() << std::endl;
-    std::cout << py::format_descriptor<StringStruct>::format() << std::endl;
+py::list print_format_descriptors() {
+    const auto fmts = {
+        py::format_descriptor<SimpleStruct>::format(),
+        py::format_descriptor<PackedStruct>::format(),
+        py::format_descriptor<NestedStruct>::format(),
+        py::format_descriptor<PartialStruct>::format(),
+        py::format_descriptor<PartialNestedStruct>::format(),
+        py::format_descriptor<StringStruct>::format()
+    };
+    auto l = py::list();
+    for (const auto &fmt : fmts) {
+        l.append(py::cast(fmt));
+    }
+    return l;
 }
 
-void print_dtypes() {
-    std::cout << (std::string) py::dtype::of<SimpleStruct>().str() << std::endl;
-    std::cout << (std::string) py::dtype::of<PackedStruct>().str() << std::endl;
-    std::cout << (std::string) py::dtype::of<NestedStruct>().str() << std::endl;
-    std::cout << (std::string) py::dtype::of<PartialStruct>().str() << std::endl;
-    std::cout << (std::string) py::dtype::of<PartialNestedStruct>().str() << std::endl;
-    std::cout << (std::string) py::dtype::of<StringStruct>().str() << std::endl;
+py::list print_dtypes() {
+    const auto dtypes = {
+        py::dtype::of<SimpleStruct>().str(),
+        py::dtype::of<PackedStruct>().str(),
+        py::dtype::of<NestedStruct>().str(),
+        py::dtype::of<PartialStruct>().str(),
+        py::dtype::of<PartialNestedStruct>().str(),
+        py::dtype::of<StringStruct>().str()
+    };
+    auto l = py::list();
+    for (const auto &s : dtypes) {
+        l.append(s);
+    }
+    return l;
 }
 
 py::array_t<int32_t, 0> test_array_ctors(int i) {
diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py
index 783f6ad..73da346 100644
--- a/tests/test_numpy_dtypes.py
+++ b/tests/test_numpy_dtypes.py
@@ -13,39 +13,35 @@
 
 
 @pytest.requires_numpy
-def test_format_descriptors(capture):
+def test_format_descriptors():
     from pybind11_tests import get_format_unbound, print_format_descriptors
 
     with pytest.raises(RuntimeError) as excinfo:
         get_format_unbound()
     assert 'unsupported buffer format' in str(excinfo.value)
 
-    with capture:
-        print_format_descriptors()
-    assert capture == """
-        T{=?:x:3x=I:y:=f:z:}
-        T{=?:x:=I:y:=f:z:}
-        T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:}
-        T{=?:x:3x=I:y:=f:z:12x}
-        T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x}
-        T{=3s:a:=3s:b:}
-    """
+    assert print_format_descriptors() == [
+        "T{=?:x:3x=I:y:=f:z:}",
+        "T{=?:x:=I:y:=f:z:}",
+        "T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:}",
+        "T{=?:x:3x=I:y:=f:z:12x}",
+        "T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x}",
+        "T{=3s:a:=3s:b:}"
+    ]
 
 
 @pytest.requires_numpy
-def test_dtype(capture):
+def test_dtype():
     from pybind11_tests import print_dtypes, test_dtype_ctors, test_dtype_methods
 
-    with capture:
-        print_dtypes()
-    assert capture == """
-        {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}
-        [('x', '?'), ('y', '<u4'), ('z', '<f4')]
-        [('a', {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}), ('b', [('x', '?'), ('y', '<u4'), ('z', '<f4')])]
-        {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}
-        {'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}], 'offsets':[8], 'itemsize':40}
-        [('a', 'S3'), ('b', 'S3')]
-    """
+    assert print_dtypes() == [
+        "{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}",
+        "[('x', '?'), ('y', '<u4'), ('z', '<f4')]",
+        "[('a', {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}), ('b', [('x', '?'), ('y', '<u4'), ('z', '<f4')])]",
+        "{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}",
+        "{'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}], 'offsets':[8], 'itemsize':40}",
+        "[('a', 'S3'), ('b', 'S3')]"
+    ]
 
     d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
                    'offsets': [1, 10], 'itemsize': 20})
@@ -58,7 +54,7 @@
 
 
 @pytest.requires_numpy
-def test_recarray(capture):
+def test_recarray():
     from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
                                 print_rec_simple, print_rec_packed, print_rec_nested,
                                 create_rec_partial, create_rec_partial_nested)
@@ -77,21 +73,17 @@
         assert_equal(arr, elements, packed_dtype)
 
         if dtype == simple_dtype:
-            with capture:
-                print_rec_simple(arr)
-            assert capture == """
-                s:0,0,0
-                s:1,1,1.5
-                s:0,2,3
-            """
+            assert print_rec_simple(arr) == [
+                "s:0,0,0",
+                "s:1,1,1.5",
+                "s:0,2,3"
+            ]
         else:
-            with capture:
-                print_rec_packed(arr)
-            assert capture == """
-                p:0,0,0
-                p:1,1,1.5
-                p:0,2,3
-            """
+            assert print_rec_packed(arr) == [
+                "p:0,0,0",
+                "p:1,1,1.5",
+                "p:0,2,3"
+            ]
 
     nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
 
@@ -104,13 +96,11 @@
     assert_equal(arr, [((False, 0, 0.0), (True, 1, 1.5)),
                        ((True, 1, 1.5), (False, 2, 3.0)),
                        ((False, 2, 3.0), (True, 3, 4.5))], nested_dtype)
-    with capture:
-        print_rec_nested(arr)
-    assert capture == """
-        n:a=s:0,0,0;b=p:1,1,1.5
-        n:a=s:1,1,1.5;b=p:0,2,3
-        n:a=s:0,2,3;b=p:1,3,4.5
-    """
+    assert print_rec_nested(arr) == [
+        "n:a=s:0,0,0;b=p:1,1,1.5",
+        "n:a=s:1,1,1.5;b=p:0,2,3",
+        "n:a=s:0,2,3;b=p:1,3,4.5"
+    ]
 
     arr = create_rec_partial(3)
     assert str(arr.dtype) == "{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}"
@@ -142,19 +132,17 @@
 
 
 @pytest.requires_numpy
-def test_string_array(capture):
+def test_string_array():
     from pybind11_tests import create_string_array, print_string_array
 
     arr = create_string_array(True)
     assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
-    with capture:
-        print_string_array(arr)
-    assert capture == """
-        a='',b=''
-        a='a',b='a'
-        a='ab',b='ab'
-        a='abc',b='abc'
-    """
+    assert print_string_array(arr) == [
+        "a='',b=''",
+        "a='a',b='a'",
+        "a='ab',b='ab'",
+        "a='abc',b='abc'"
+    ]
     dtype = arr.dtype
     assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
     assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
diff --git a/tests/test_numpy_vectorize.cpp b/tests/test_numpy_vectorize.cpp
index a36b7d0..f05c655 100644
--- a/tests/test_numpy_vectorize.cpp
+++ b/tests/test_numpy_vectorize.cpp
@@ -35,7 +35,7 @@
     m.def("vectorized_func3", py::vectorize(my_func3));
 
     /// Numpy function which only accepts specific data types
-    m.def("selective_func", [](py::array_t<int, py::array::c_style>) { std::cout << "Int branch taken." << std::endl; });
-    m.def("selective_func", [](py::array_t<float, py::array::c_style>) { std::cout << "Float branch taken." << std::endl; });
-    m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { std::cout << "Complex float branch taken." << std::endl; });
+    m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; });
+    m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; });
+    m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; });
 }
diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py
index 6fcf808..73da819 100644
--- a/tests/test_numpy_vectorize.py
+++ b/tests/test_numpy_vectorize.py
@@ -59,18 +59,12 @@
 
 
 @pytest.requires_numpy
-def test_type_selection(capture):
+def test_type_selection():
     from pybind11_tests import selective_func
 
-    with capture:
-        selective_func(np.array([1], dtype=np.int32))
-        selective_func(np.array([1.0], dtype=np.float32))
-        selective_func(np.array([1.0j], dtype=np.complex64))
-    assert capture == """
-        Int branch taken.
-        Float branch taken.
-        Complex float branch taken.
-    """
+    assert selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
+    assert selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
+    assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
 
 
 @pytest.requires_numpy
diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp
index 0ede5e3..901f05e 100644
--- a/tests/test_opaque_types.cpp
+++ b/tests/test_opaque_types.cpp
@@ -38,21 +38,21 @@
         .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
 
     m.def("print_opaque_list", [](const StringList &l) {
-        std::cout << "Opaque list: [";
+        std::string ret = "Opaque list: [";
         bool first = true;
         for (auto entry : l) {
             if (!first)
-                std::cout << ", ";
-            std::cout << entry;
+                ret += ", ";
+            ret += entry;
             first = false;
         }
-        std::cout << "]" << std::endl;
+        return ret + "]";
     });
 
     m.def("return_void_ptr", []() { return (void *) 0x1234; });
-    m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; });
+    m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
     m.def("return_null_str", []() { return (char *) nullptr; });
-    m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; });
+    m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
 
     m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
         StringList *result = new StringList();
diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py
index 5c2ca92..9436863 100644
--- a/tests/test_opaque_types.py
+++ b/tests/test_opaque_types.py
@@ -1,64 +1,48 @@
 import pytest
 
 
-def test_string_list(capture):
+def test_string_list():
     from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list
 
     l = StringList()
     l.push_back("Element 1")
     l.push_back("Element 2")
-    with capture:
-        print_opaque_list(l)
-    assert capture == "Opaque list: [Element 1, Element 2]"
+    assert print_opaque_list(l) == "Opaque list: [Element 1, Element 2]"
     assert l.back() == "Element 2"
 
     for i, k in enumerate(l, start=1):
         assert k == "Element {}".format(i)
     l.pop_back()
-    with capture:
-        print_opaque_list(l)
-    assert capture == "Opaque list: [Element 1]"
+    assert print_opaque_list(l) == "Opaque list: [Element 1]"
 
     cvp = ClassWithSTLVecProperty()
-    with capture:
-        print_opaque_list(cvp.stringList)
-    assert capture == "Opaque list: []"
+    assert print_opaque_list(cvp.stringList) == "Opaque list: []"
 
     cvp.stringList = l
     cvp.stringList.push_back("Element 3")
-    with capture:
-        print_opaque_list(cvp.stringList)
-    assert capture == "Opaque list: [Element 1, Element 3]"
+    assert print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]"
 
 
-def test_pointers(capture, msg):
-    from pybind11_tests import (return_void_ptr, print_void_ptr, ExampleMandA,
-                                print_opaque_list, return_null_str, print_null_str,
+def test_pointers(msg):
+    from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA,
+                                print_opaque_list, return_null_str, get_null_str_value,
                                 return_unique_ptr, ConstructorStats)
 
-    with capture:
-        print_void_ptr(return_void_ptr())
-    assert capture == "Got void ptr : 0x1234"
-    with capture:
-        print_void_ptr(ExampleMandA())  # Should also work for other C++ types
-    assert "Got void ptr" in capture
+    assert get_void_ptr_value(return_void_ptr()) == 0x1234
+    assert get_void_ptr_value(ExampleMandA())  # Should also work for other C++ types
     assert ConstructorStats.get(ExampleMandA).alive() == 0
 
     with pytest.raises(TypeError) as excinfo:
-        print_void_ptr([1, 2, 3])  # This should not work
+        get_void_ptr_value([1, 2, 3])  # This should not work
     assert msg(excinfo.value) == """
         Incompatible function arguments. The following argument types are supported:
-            1. (arg0: capsule) -> None
+            1. (arg0: capsule) -> int
             Invoked with: [1, 2, 3]
     """
 
     assert return_null_str() is None
-    with capture:
-        print_null_str(return_null_str())
-    assert capture == "Got null str : 0x0"
+    assert get_null_str_value(return_null_str()) is not None
 
     ptr = return_unique_ptr()
     assert "StringList" in repr(ptr)
-    with capture:
-        print_opaque_list(ptr)
-    assert capture == "Opaque list: [some value]"
+    assert print_opaque_list(ptr) == "Opaque list: [some value]"
diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py
index f2efb6b..27b0222 100644
--- a/tests/test_virtual_functions.py
+++ b/tests/test_virtual_functions.py
@@ -173,7 +173,7 @@
     assert obj.lucky_number() == -4.25
 
 
-def test_move_support(capture, msg):
+def test_move_support(capture):
     from pybind11_tests import NCVirt, NonCopyable, Movable
 
     class NCVirtExt(NCVirt):