How to properly unit-test a linked list (using Python)?

3.4k Views Asked by At

I'm new to TDD. I've created all the main functions (insert, search, remove etc.). This is my insert_beginning() function:

def insert_beginning(self, node):
    '''
    Inserts a Node to the beginning of the list.
    '''
    node.set_next(self.head)
    self.head = node

My question is, how do I properly unit-test this function? The only way I can thing of is:

class ListFunctionsTest(unittest.TestCase):

    def setUp(self): 
        self.list1 = LinkedList()
        self.node1 = Node(1)

    def test_insert_beginning(self):
        self.list1.insert_beginning(self.node1)
        self.assertEqual(self.list1.__str__(), "1")

but then the test_insert_beginning() function is dependent on my

__str__() # string representation of my linked list

function. I have a feeling that the way I'm testing it is not correct (because the moment I decide to change the way my linked list is represented, then I'd end up having to rewrite my test cases). Is there a way to test my insert_beginning() function without depending on another function which I created / customized?

Edit: For those wondering, currently, the string representation of my linked list is just a string representation of my nodes separated by commas. For example, a linked list with the nodes 1, 2 and "a" would be represented like this:

1, 2, "a"

However, I am planning on changing my linked list's string representation (planning on changing the __ str __() function). This is when I realized that the way I am unit testing might be incorrect.

Edit 2 (a comment suggested that I create a function which helps me find the index of an item in the linked list): Assume that a function called index_of(self, item) exists, and this function finds the index of an item. Assume that this is the unit test for the index_of(self, item), and assume that the test cases successfully pass.

def test_index_of(self):
    myList = LinkedList()
    node1 = Node(1)
    node2 = Node(2)
    node3 = Node(3)
    myList.head = node1
    node1.next = node2
    node2.next = node3

    self.assertEqual(self.myList.index_of(1), 0)
    self.assertEqual(self.myList.index_of(2), 1)
    self.assertEqual(self.myList.index_of(3), 2)

Now, is it okay for me to rely on the index_of(self, item) function to determine if insert_beginning(self, node) is working correctly? In other words, is it okay if my test_insert_beginning() function is:

class ListFunctionsTest(unittest.TestCase):

    def setUp(self): 
        self.list1 = LinkedList()
        self.node1 = Node(1)

    def test_insert_beginning(self):
        self.list1.insert_beginning(self.node1)
        self.assertEqual(self.list1.index_of(1), 0)
1

There are 1 best solutions below

2
On BEST ANSWER

You have a good point. You don't want to tie yourself to an arbitrary String representation of the list, which will probably change. The "proper" way to check this would be to check the values in the list. I.e., instead of checking the string representation, you should check all your post conditions seperatly:

  • The first value is 1

  • The previous value doesn't exist (Does whatever you want to happen on error)

  • The next value does the same as the previous value

  • The size is 1

  • ...

    Of course for the methods that support this you will have to have separate unit tests.