Skip to main content
Became Hot Network Question
Summarise the purpose, not the concerns, in the title
Link
Toby Speight
  • 88.7k
  • 14
  • 104
  • 327

What is the Pythonic way to write this test Test suite that generatesfor population-count function, using random input?

Source Link
joseville
  • 516
  • 2
  • 10

What is the Pythonic way to write this test suite that generates random input?

For the purpose of this discussion, I have the following function:

def countSetBits(num):
  cnt = 0
  while num:
    cnt += num & 0b1
    num >>= 1
  return cnt

It counts the number of set bits in a given num's binary representation. For example, take 10 whose binary rep is 0b1010 -- countSetBits(10) should equal 2.

I have written a "test suite" that generates random input -- numbers of known set bit count and use that to test my countSetBits function.

import random
import unittest

class TestCountSetBits(unittest.TestCase):
    NUM_TESTS = 100
    MAX_SET_BIT_CNT = 10
    def test_suite(self):
        for _ in range(self.NUM_TESTS):
            k = expectedCnt = random.randint(0, self.MAX_SET_BIT_CNT)

            # Generate a random integer with `k` set bits
            setBitPositions = random.sample(range(k * 2), k)
            num = sum(0b1 << pos for pos in setBitPositions)
            computedCnt = countSetBits(num)
            self.assertEqual(computedCnt,
                             expectedCnt,
                             msg=f'Got {computedCnt}, but expected {expectedCnt}')
        print('Success!')

TestCountSetBits().test_suite()

My questions are:

  1. Should I use cls instead of self?
  2. Is there a more pythonic way to write this "test suite". I may be reading too much into this, but Python Doc's unittest page has a Basic Example in which each def test_* has only one assertEqual. My def test_suite has the assertEqual inside a for loop. Is this bad style?
  3. Any suggestions are welcome! Thanks!

Scrolling down the unittest page, I see subTest which may tidy things up:

class TestCountSetBits(unittest.TestCase):
    NUM_TESTS = 100
    MAX_SET_BIT_CNT = 10
    def test_suite(self):
        for _ in range(self.NUM_TESTS):
            k = expectedCnt = random.randint(0, self.MAX_SET_BIT_CNT)

            # Generate a random integer with `k` set bits
            setBitPositions = random.sample(range(k * 2), k)
            num = sum(0b1 << pos for pos in setBitPositions)
            computedCnt = countSetBits(num)

            # Diff starts here
            with self.subTest():
                self.assertEqual(computedCnt,
                                 expectedCnt,
                                 msg=f'Got {computedCnt}, but expected {expectedCnt}')
            # Diff ends here

        print('Success!')

TestCountSetBits().test_suite()