0

I am new to programming and have implemented an onlinestore in python with a number of different features.

One of the submission requirements is to show evidence of testing, I have read about unit unittest in python and I am just wondering how you structure the tests when functions do not have a definitive answer, for example I have a function that returns all products in a mysql database as show below;

    class TestSum(unittest.TestCase):

        def test_get_all_products(input):
            connection = get_sql_connection()
            cursor = connection.cursor()
            if input:
                query = ("SELECT * FROM `online-store`.product WHERE name like 
               '%"+input+"%';")
            else:
                query = ("SELECT * FROM `online-store`.product;")
            cursor.execute(query)
            response = cursor.fetchall()
            for row in response:
                print ("Id=",row[0],"\t","Name=",row[1] , "\t","Price =£",row[2],"\t"," 
                        Supplier",row[4])

           return response

I am wondering how I would test this function, what should the syntax be

  • you say 'structuring tests' (which is fine) but then you ask how to test a function, but the only function you provide is a *test* function. What do you want to do? Presumably you don't want to write unittests for your unitests... additionally your unitest doesn't actually have any asserts in it, so it's just a smoke test. What's the question here? – 2e0byo Oct 25 '21 at 11:00
  • Additionally, where does your unittest get `input` from? and `input` is a poor name for a variable, since it shadows the builtin `input()` – 2e0byo Oct 25 '21 at 11:01

1 Answers1

0

Create a setUpClass method that...

  1. Creates an empty database and populates it with specific data.
  2. Creates the system under test (sut), giving it a reference to the connection (either the connection string, or maybe the connection object itself). Store the sut in a class variable so the tests can access it.

Create a tearDownClass method to delete the database.

If any of your tests will modify the database, use setUp and tearDown instead of setUpClass and tearDownClass.

Create a set of test methods that tell the story of how your function is supposed to behave. Based on your function here is a list to get you started...

  • When input is None ...
  • When input is not None ...
  • When input matches nothing in the table ...
  • When input matches one item in the table ...
  • When input matches, say, 5 items in the table ...

For each test method, select a specific value for input for which you can predict the result of your function based on your test data.

If any of the tests updates the database, you'll also want to create a tearDown

It looks like most of the observable behavior of the function is in what it prints. So you're going to need to capture stdout and possibly stderr. This SO may help get you started How to capture the stdout/stderr of a unittest in a variable? .


All that said, if you have control over the function that you are testing, you might consider refactoring it to make it more testable. For example, separate out the query code from the formatting of the results as a string; and separate out the printing of the string from the formatting of the string. Something like this...

def get_all_products(connection, input):
    results = _query_products_for_items_like(connection, input)
    string = _format_query_results(result)
    print(string)

def _query_products_for_items_like(connection, input):
    ...
    return rows

def _format_query_results(results):
    response_strings = []
    ...
    return '\n'.join(response_strings)

Now you can test _query_products_for_items_like and _format_query_results in isolation. And you may not need to test get_all_products at all considering how simple its logic is.

Stoney
  • 698
  • 5
  • 11