0

I am programming a tree for an assignment. Part of this assignment requires us to update the 'imbalance' of the tree at a Node-level. I have an instance variable 'imbalance' that tracks this for each node. Each time I push to the tree I must update this variable.

When unit-testing this creates a problem: the instance variable is not 'reset' or otherwise has unpredictable behaviour between tests because (I believe) of the way the unit tests cache the class. If I change this variable under the first test it will pass all the assertions but on subsequent tests it will fail because it is persisting between them and causing weird problems. I also have to use a getter to access the imbalance variable from each instance of the node.

I know how to fix this, but unfortunately, I cannot change the unit tests (they are fixed for the assignment) so how do I keep track of this variable and change it without having side affects on other unit tests?

EDIT: ~ full disclosure ~ I'm only sharing this expressly for the purpose of diagnosing issues with the unit tests not to seek out help with the actual data structure. Here's two unit tests that demonstrate the odd issue:

def setUp(self):
    """
    Set up the tree to be used throughout the test
    This is the tree given in the sample
    A(5)
    /   \
    C(2) D(8)
    /
    B(10)
    """

    self.A = Node(5)
    self.B = Node(10)
    self.C = Node(2)
    self.D = Node(8)
    self.C.add_left_child(self.B)
    self.A.add_left_child(self.C)
    self.A.add_right_child(self.D)

def test_get_imbalance(self):
    """
    Test that the sample tree returns the correct imbalance
    """
    assert_equal(self.A.get_imbalance(), 4, "A has an imbalance of 4")
    assert_equal(self.C.get_imbalance(), 10, "C has an imbalance of 10")
    assert_equal(self.D.get_imbalance(), 0, "D has no imbalance")
    assert_equal(self.B.get_imbalance(), 0, "B has no imbalance")

def test_update_weight(self):
    """
    Test that the sample tree updates the weight correctly
    """
    #self.A.update_weight(10)
    assert_equal(self.A.get_imbalance(), 4, "A has an imbalance of 4")
    assert_equal(self.C.get_imbalance(), 10, "C has an imbalance of 10")
    assert_equal(self.D.get_imbalance(), 0, "D has no imbalance")
    assert_equal(self.B.get_imbalance(), 0, "B has no imbalance")

Exactly the same! But the second yields the default value created in init for the relevant var whereas the one above returns the correct value. Hope that gives a better idea.

  • 1
    Show us the relevant code and test! – Klaus D. Mar 27 '22 at 11:21
  • 1
    Are you using setUp and tearDown methods correctly? it would be nice to see some code... – Salek Mar 27 '22 at 11:23
  • Bearing in mind that this is an assignment and our university has a VERY strict policy on help I can't share the exact code. Here are the relevant details: there is only a setUp method (no tearDown) method and again I have no control over that due to automated testing. The nodes are linked to each other and I recursively update them each time there is a change in the tree to reflect the imbalance. The test calls the getter which returns the relevant instance var. – Ranch Mayonaise Mar 27 '22 at 11:25
  • 1
    Seems like you have little control over the testing environment. How about a [deep copy](https://docs.python.org/3/library/copy.html) of the tree in the first phase? – Salek Mar 27 '22 at 11:29
  • Yes I was thinking about that. Would you mind elaborating on what you mean by first phase? The nodes are essentially just pointers and I only have control over the file with the actual data structure not the unit tests. I just cloned them onto my machine locally to see why the results were so strange. – Ranch Mayonaise Mar 27 '22 at 11:36
  • 1
    I mean it shouldn't be the most efficient way and you might get into time-limit error (if there is one for your tests), but essentially use a variable to store the unchanged first-hand data, maybe save it in setUp method if you have access to it. – Salek Mar 27 '22 at 11:48
  • 1
    If the data is stored in a list, see how to [deep copy a list](https://stackoverflow.com/questions/17873384/how-to-deep-copy-a-list) – Salek Mar 27 '22 at 11:49

1 Answers1

1

In setUp you might want to save the original Nodes with a deep copy:

import copy

A_prime = copy.deepcopy(A)

Now should A is changed in value, A_prime will be untouched. (since it is completely a new object)

Salek
  • 449
  • 1
  • 10
  • 19
  • Thanks so much. Unfortunately I don't have access to setUp :( – Ranch Mayonaise Mar 27 '22 at 12:20
  • 1
    @RanchMayonaise okay, where do you have access to? is it a function somewhere else that you should complete? – Salek Mar 27 '22 at 12:24
  • Yes. There's a function that updates all the other Node's values (recursively.) It is called each time a node is linked into the tree. In the original post in the example, there is also a getter which retrieves these. But in between the test cases calling the function again to update the nodes does nothing... – Ranch Mayonaise Mar 27 '22 at 12:28