Code Testing#

Open In Colab

Q&A

Q: How can I link pandas t google sheets and how could one write there own methods for pandas?
A: There is an additional package that most people use to read directly from googlesheets (called gspread) [I will note that in R this is a bit more straightforward than in python, but that’s neither here nor thtere.] As for writing your own methods, the most typical way would be to write a new class that inherits from the pandas object (for example a DataFrame) and adds additional methods - we briefly touched on inheritance. That said, while it’s possible, pandas has a TON of methods so it’s rare that you’d need to write one on your own.

Q: how familiar should we be with setting up an array ourselves?
A: Understand it conceptually, but you don’t need to memorize the syntax to do so.

Q: I was confused on the practice problem we worked on when it mentioned 3x3, I was just wondering whenever we see something like this is it basically telling us we have to create 3 lists inside of one list?
A: Kind of. 3x3 indicates the rows and columns. So 4x2 would be 4 rows (the first number) and 2 columns (the second number)

Q: I’m still a bit unsure about when to use NumPy vs. pandas, and how to choose the right one when working with data. Also, I’d like more practice with writing and running scripts from the terminal.
A: If you’re doing linear algebra/matrix math, numpy. Otherwise, if working with a dataset that you want to do some analysis on, it’s almost always pandas. Your final exam will focus on pandas (As will your A5). We introduce numpy to lay the foundation for discussing pandas.

Q: Also, I’d like more practice with writing and running scripts from the terminal.
A: We’ll do more of this next week!

Q: What specific topics from scientific computing will we need to know for the final exam?
A: Familiarity with numpy and pandas (their goals, main objects, etc.) and the ability to interact with pandas DataFrame objects. You do not need to memorize available methods, but if I tell you what methods do, you need to know how to use them.

Course Announcements

Due this week:

  • CL8 due Fri

  • A5 due Sun

  • Complete E2

Notes:

  • Please complete your SETs (especially for TAs/IAs) by 8AM Sat

  • Retest (E1 or E2) will be available on PrairieTest tomorrow Fri 5/30

  • Reminder to complete the Food Insecurity Survey (by Friday)

Final Exam#

  • There will a handful of MC and SA questions

  • The bulk of the exam will be a “mini project” focused on the material since E2. This will involve:

    • Debugging a function or two; these will use pandas/interact with data

    • These will be stored in a module (.py file)

    • maybe writing/executing a script that uses these functions

    • Writing a test function or two using unittest (we’re discussing this today!)

    • using good code style

  • There will be a practice exam. We will discuss putting all of these pieces together in class next week.

Code Testing#

  1. Motivation

  2. Some Testing Practices

  3. unittest Fundamentals

  4. Try It Out!

Code Testing: a process to ensure that your code runs correctly

Part I: Motivation#

Why should we test our code?

Writing Good Code#

All in all, write code that is:

  • Well organized (follows a style guide)

  • Tested

  • Documented

And you will have understandable, maintainable, and trustable code.

Four Types of Code Testing#

  1. Unit tests (primary focus): test functions & objects to ensure that the code is behaving as expected

  2. Smoke tests: preliminary tests to check basic functionality; checks if something runs, but not necessarily if it does the right thing (gut check)

  3. Integration tests: test functions, classes & modules interacting

  4. System tests: tests end-to-end behavior

Unit Tests#

  • One test for each “piece” of your code (function, class, etc.)

  • unittest will let you know which tests pass/fail/throw an error

  • Testing “edge (atypical) cases”

  • Help you resist the urge to assume computers will act how you think it will work

Part II: Some Testing Practices#

How to Write Tests#

Given a function or class you want to test:

  • You need to have an expectation for what it should do

  • Write out some example cases, with known answers

  • Use assert to check that your example cases do run as expected

  • Collect these examples into test functions, stored in test files

Test Driven Development#

In software development, test-driven development is an approach in which you write tests first - and then write code to pass the tests.

  • Ensures you go into writing code with a good plan / outline

  • Ensures that you have a test suite, as you can not decide to neglect to test your code after the fact you made the test suite

  • Note: when you complete (or at least write) assignments for this class, you are effectively doing test-driven development

Activity 1: Code Testing Ideas#

Please complete the following Google Form: https://forms.gle/86dnUZ7yd88trCUd8

Part III: unittest Fundamentals#

The very first step is to import the unittest framework.

import unittest

General template for testing in unittest:#

class TestName(unittest.TestCase):

    # TEST FUNCTIONS BELONG INSIDE THE CLASS
    def test_name_1(self):
        # code statements go inside here
        self.assertEqual(1, 1)

    def test_name_2(self):
        # code statements go inside here
        self.assertTrue(False)

    # ...

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestName)
    unittest.TextTestRunner(verbosity=2).run(suite)

Some testing functions in unittest:#

.assertEqual(a, b)#

Checks if a is equal to b. Similar to the expression a == b.

Note: Although it doesn’t affect the results, it’s good practice to let a be the expected value (what you think the result will be) and b be the actual value (what the result actually is).

def add(a, b):
    return a + b
# Equality testing suite
class TestEqual(unittest.TestCase):

    # First test
    def test_equal(self):
        self.assertEqual(10, add(4, 6))

    # Second test
    def test_equal_bad(self):
        self.assertEqual(11, add(4, 6))

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestEqual)
    unittest.TextTestRunner(verbosity=2).run(suite)

.assertTrue(x)#

Checks if x is True. Same as the expression bool(x) == True.

# Truth testing suite
class TestTrue(unittest.TestCase):

    def test_true(self):
        self.assertTrue(add(4, 6) == 10)

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestTrue)
    unittest.TextTestRunner(verbosity=2).run(suite)

.assertFalse(x)#

Checks if x is False. Same as the expression bool(x) == False.

# False testing suite
class TestFalse(unittest.TestCase):

    def test_false(self):
        self.assertFalse(add(4, 6) == 11)

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestFalse)
    unittest.TextTestRunner(verbosity=2).run(suite)

.assertIsInstance(a, b)#

Checks if a is of variable type b (int, float, str, bool) or is of an instance of class b. Similar to the expression isinstance(a, b) or type(a) == b.

# Instance testing suite
class TestInstances(unittest.TestCase):
    
    # First test
    def test_instance(self):
        self.assertIsInstance('Hello!', str)

    # Second test
    def test_instance_bad(self):
        self.assertIsInstance(3.14, int)

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestInstances)
    unittest.TextTestRunner(verbosity=2).run(suite)

.assertIsNone(x)#

Checks if x is None. Similar to the expression x is None.

def return_none():
    return
# None testing suite
class TestNone(unittest.TestCase):

    # First test
    def test_none_1(self):
        self.assertIsNone(return_none())

    # Second test
    def test_none_append(self):
        lst = []
        self.assertIsNone(lst.append(1))

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestNone)
    unittest.TextTestRunner(verbosity=2).run(suite)

.assertIn(a, b)#

Checks for membership, if a belongs in b. Same as the expression a in b.

# Membership testing suite
class TestIn(unittest.TestCase):

    fruits = ['apples', 'bananas', 'oranges']

    # First test
    def test_membership(self):
        self.assertIn('apples', self.fruits)

    # Second test
    def test_membership_bad(self):
        self.assertIn('pears', self.fruits)

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestIn)
    unittest.TextTestRunner(verbosity=2).run(suite)

Putting it all together…#

class TestAllAdd(unittest.TestCase):

    def test_all(self):
        self.assertEqual(10, add(4, 6))
        self.assertEqual(11, add(4, 6))
        self.assertTrue(add(4, 6) == 10)
        self.assertFalse(add(4, 6) == 11)
        
if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestAllAdd)
    unittest.TextTestRunner(verbosity=2).run(suite)

Part IV: Try It Out!#

Make a class named Person that has two instance attributes: name and age. Be sure that they are assigned to user-specified values. Then, make a method called birthday() that increments age by 1 and returns the string “Happy Birthday!”

Then, create a test class with only one test function that does the following:

  • Create an instance of the Person class

  • Write the following tests, making sure that they pass:

    • The instance is of instance Person

    • The instance’s name is equal to the name you gave it

    • The instance’s age is equal to the age you gave it

    • Call the birthday() function and write a test checking if the instance’s age got incremented by 1

Submit your responses to this Google Form: https://forms.gle/mRY9zxSxGFuSY6A38

# TRY IT OUT