When we implemented the convert_isbn_10_to_13()
method, we decided to use a custom exception (FormatException
) to indicate that there was something wrong with the ISBN-10 string that is provided as input.
def convert_isbn_10_to_13(isbn10_code_string: str) -> str: if not ISBNValidator.validate_isbn10(isbn10_code_string): raise ISBNValidator.FormatException(f"{isbn10_code_string} is not a valid ISBN-10 code string.")
From a design standpoint, this is a good thing, but it presents a small challenge when we think about how we might test it within the confines of the Python unittest
framework. Luckily the developers of the unittest module thought of this and we can assert whether or not a particular function raises a particular exception.
The formatting is slightly different, but within the context of our ISBN practice exercise, the code looks like this:
def test_convert_isbn_10_to_13(self): ... # Test invalid input invalid_isbn_10 = "1-55404-294-X" with self.assertRaises(ISBNValidator.FormatException): ISBNValidator.convert_isbn_10_to_13(invalid_isbn_10)
Some things to notice about this mechanism:
- It is really helpful to use custom exceptions in these cases. That way, there is an easy mechanism to check that a function is throwing the proper exception for the right reason, and other (unexpected) exceptions actually cause the test execution to break. This would be more difficult if we merely tried to
raise Exception()
from the method. - Using the
with
clause allows for more than one line to be executed while waiting for the exception. If the code finishes thewith
block without an exception, the test will fail.
Once we integrate this code into our test suite, we are now able to ensure that we are raising an exception when presented with invalid input. Hooray!
Next, we will try to answer the question: “Are my tests exercising all of the code I’ve written?” by learning a bit about Python code coverage tools.
For reference, here is the code in it’s current state.