\[ [Index](index.md) | [Exercise 5.5](ex5_5.md) | [Exercise 6.1](ex6_1.md) \]

# Exercise 5.6

*Objectives:*

- Learn how to use Python's unittest module

*Files Created:* `teststock.py`

In this exercise, you will explore the basic mechanics of using
Python's `unittest` modules.

## (a) Preliminaries

In previous exercises, you created a file `stock.py` that contained
a `Stock` class.   In a separate file, `teststock.py`, define the following
testing code:

```python
# teststock.py

import unittest
import stock

class TestStock(unittest.TestCase):
    def test_create(self):
        s = Stock('GOOG', 100, 490.1)
        self.assertEqual(s.name, 'GOOG')
        self.assertEqual(s.shares, 100)
        self.assertEqual(s.price, 490.1)

if __name__ == '__main__':
    unittest.main()
```

Make sure you can run the file:

```
 bash % python3 teststock.py
 .
 ------------------------------------------------------------------```
 Ran 1 tests in 0.001s

 OK
 bash %
```

## (b) Unit testing

Using the code in `teststock.py` as a guide, extend the `TestStock` class
with tests for the following:

- Test that you can create a `Stock` using keyword arguments such as `Stock(name='GOOG',shares=100,price=490.1)`.
- Test that the `cost` property returns a correct value
- Test that the `sell()` method correctly updates the shares.
- Test that the `from_row()` class method creates a new instance from good data.
- Test that the `__repr__()` method creates a proper representation string.
- Test the comparison operator method `__eq__()`

## (c) Unit tests with expected errors

Suppose you wanted to write a unit test that checks for an exception.
Here is how you can do it:

```python
class TestStock(unittest.TestCase):
    ...
    def test_bad_shares(self):
        s = stock.Stock('GOOG', 100, 490.1)
        with self.assertRaises(TypeError):
             s.shares = '50'
    ...
```

Using this test as a guide, write unit tests for the following failure modes:

- Test that setting `shares` to a string raises a `TypeError`
- Test that setting `shares` to a negative number raises a `ValueError`
- Test that setting `price` to a string raises a `TypeError`
- Test that setting `price` to a negative number raises a `ValueError`
- Test that setting a non-existent attribute `share` raises an `AttributeError`

In total, you should have around a dozen unit tests when you're done.

**Important Note**

For later use in the course, you will want to have a fully working
`stock.py` and `teststock.py` file.  Save your work in progress if you
have to, but you are strongly encouraged to copy the code from
`Solutions/5_6` if things are still broken at this point.

We're going to use the `teststock.py` file as a tool for improving the `Stock` code
later.  You'll want it on hand to make sure that the new code behaves the same way
as the old code.

\[ [Solution](soln5_6.md) | [Index](index.md) | [Exercise 5.5](ex5_5.md) | [Exercise 6.1](ex6_1.md) \]

----
`>>>` Advanced Python Mastery  
`...` A course by [dabeaz](https://www.dabeaz.com)  
`...` Copyright 2007-2023  

![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)
