My recommendation would be to split out the asking and checking of input from the getting and setting of properties on the engine.
For example:
def ask_voice():
readers_voice = input("Voice: ").lower().strip()
if readers_voice not in ["female", "male"]:
raise ValueError("Choose from male or female")
return readers_voice
def read_with_voice(n, readers_voice):
voices = engine.getProperty("voices")
if readers_voice == "female":
engine.setProperty("voice", voices[1].id)
elif readers_voice == "male":
engine.setProperty("voice", voices[0].id)
engine.setProperty("rate", 150)
rate = engine.getProperty("rate")
engine.say(n)
engine.runAndWait()
def pdftospeech(n):
readers_voice = ask_voice()
read_with_voice(n, readers_voice)
The test for ask_voice
is then more straightforward:
import unittest
from unittest import mock
def ask_voice():
readers_voice = input("Voice: ").lower().strip()
if readers_voice not in ["female", "male"]:
raise ValueError("Choose from male or female")
return readers_voice
class Test101(unittest.TestCase):
def test_ask_male(self):
with mock.patch('builtins.input', return_value="MaLe"):
self.assertEqual('male', ask_voice())
def test_ask_female(self):
with mock.patch('builtins.input', return_value="FeMaLe"):
self.assertEqual('female', ask_voice())
def test_ask_fail(self):
with mock.patch('builtins.input', return_value="mail"):
self.assertRaises(ValueError, ask_voice)
if __name__ == '__main__':
unittest.main(verbosity=2)
This test gave the following output:
test_ask_fail (__main__.Test101) ... ok
test_ask_female (__main__.Test101) ... ok
test_ask_male (__main__.Test101) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK