0

Am new in unit testing, I have a function which doesn't return anything and generates numbers randomly from a certain number to another, I read about the mocking library but it's still confusing to me, how can I unit test this function.

What I want to test

  1. Testing if numbers are generated between 1000 and 8876.
  2. Checking the positions of different numbers with a 4 -digit values are not equal to each other. e.g 1234, this number is allowed because it has no repetitions. but 1123 is not allowed because it has a number repeated in different positions. That's what the while loop is doing.

I tried to read similar questions e.g link 1 link 2 but I couldn't connect to this scenario

def num(self): 



                    random = randint(1000, 8876) 

                    random = list(map(int, str(random))) 

                    while random[0] == random[1] or random[0] == random[2] or random[0] == random[3] or random[1] == random[2] or random[1] == random[3] or random[2] == random[3]: 

                            random = randint(1000, 8876) 

                            random = list(map(int, str(random))) 

                    num = "" 

                    self.num = int(num.join(map(str,random))) 
Idris Stack
  • 546
  • 1
  • 14
  • 36

2 Answers2

0

split this up into two parts, one part which generates a random number and one part which checks that the number satisfies your rules.

something like:

number = generateNumber(1000, 8876) // this is where you do the random generation
verifyNumber(number) // this is another method where you check the rules
//do whatever else after this.

All you have to do now is test your business rules, you can throw whatever numbers you want at your second method, without depending on anything random.

you can't test randomness and there's no point testing library methods. Test your rules, by eliminating the things that you cannot control.

Andrei Dragotoniu
  • 6,155
  • 3
  • 18
  • 32
0

First of all, if you post code, please only post complete and executable code. In your case, self.num is defined twice, once as variable and once as function. Also, there is no class body around the function.

It is important to post complete code, because the surrounding structure could be of importance for the answer. In your case, I just have to assume how the containing class looks like, therefore the answer might not be applicable to your problem.

This is how I would write a unit test for your specific problem:

from random import randint
import unittest

class RandomGen:
    def __init__(self):
        self.num = None

    def compute_num(self):
        random = randint(1000, 8876)
        random = list(map(int, str(random)))
        while random[0] == random[1] or random[0] == random[2] or \
              random[0] == random[3] or random[1] == random[2] or \
              random[1] == random[3] or random[2] == random[3]:
            random = randint(1000, 8876)
            random = list(map(int, str(random)))
        num = ""
        self.num = int(num.join(map(str,random)))

class RandomGenTest(unittest.TestCase):

    # It's hard to test random number generators deterministically.
    # Therefore, just repeat it a bunch of times to increase the chance for
    # incorrect results to show up. In this case, 10000 times.

    def test_range(self):
        gen = RandomGen()     
        for i in range(10000):
            gen.compute_num()
            self.assertGreaterEqual(gen.num, 1000)
            self.assertLessEqual(gen.num, 8876)

    def test_duplicates(self):
        gen = RandomGen()     
        for i in range(10000):
            gen.compute_num()
            numbers = list(map(int, str(gen.num)))
            self.assertEqual(len(numbers), len(set(numbers)))

if __name__ == '__main__':
    unittest.main()
Finomnis
  • 18,094
  • 1
  • 20
  • 27
  • "It's hard to test random number generators deterministically" . random and deterministic are mutually exclusive – Andrei Dragotoniu May 26 '19 at 11:42
  • That's exactly why it is hard. But none of that matters, to be honest, because I don't think OP asked us to fix his function, he asked us to unit test, and he asked exactly what he wanted to test. This is the answer to that question. – Finomnis May 26 '19 at 11:47
  • running something a thousands times hoping that something will happen is not an answer. you're missing the point of unit testing – Andrei Dragotoniu May 26 '19 at 11:48
  • 1
    I've seen that style of unit testing a lot of times. It's the only way of testing stuff that isn't deterministic. Especially in continuous integration, similar tests proved very useful in my past. (In my case in computer game ai, where nothing is deterministic) Not all unittests serve the purpose of _proving_ that the code is right, sometimes it is just a shot in the dark to hopefully find errors if there is no other way to test. Better than not testing at all. – Finomnis May 26 '19 at 11:53
  • you keep saying there is no other way to test, there is, you've just completely missed it. separation of concerns is the answer, get that bit right and your test will become much more useful – Andrei Dragotoniu May 26 '19 at 11:56
  • I don't think you get me. Of course there is other ways to solve the problem, and you are absolutely right that there are better ways to write that function if correctness is the main concern. But not without rewriting the function itself, which is out of scope for the question asked. But for completeness sake, I hereby admit additionally to the heuristic test there should also be a test for the condition in the while loop. Which does not render the random test useless. – Finomnis May 26 '19 at 12:05