lk-geimfari / mimesis

Mimesis is a robust data generator for Python that can produce a wide range of fake data in multiple languages.
https://mimesis.name
MIT License
4.39k stars 330 forks source link

Global seeding does not work as expected #349

Closed kairichard closed 6 years ago

kairichard commented 6 years ago

Consider the following code:

import unittest
import random

from mimesis import Food

class Test(unittest.TestCase):
    def test_food(self):
        f = Food("en")
        print(">>", f.dish())

if __name__ == "__main__":
    random.seed("123")
    unittest.main()

I would expect that for consecutive runs the same dish is printed but it's not:

>> Macaroni and Cheese
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Press ENTER or type command to continue
>> Ploye
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

The question now is whether that is expected behavior? I know there is a specific seed for each Provider. Because I find it a bit annoying, requiring me to jump a few more hoops to get this under test.

>> python --version
Python 3.5.3
>> pip freeze|grep mime
mimesis==1.0.4
lk-geimfari commented 6 years ago

@kairichard You must explicitly pass the argument seed to the data provider. Example:

>>> from mimesis import Food
>>> food = Food('en', seed=0x7b)
>>> food.dish()
'Biscuit'
>>> food = Food('en', seed=0x7b)
>>> food.dish()
'Biscuit'
lk-geimfari commented 6 years ago

@kairichard If you want to use one seed for any providers then you can use Generic data provider:

>>> from mimesis import Generic
>>> generic = Generic('de', seed=0xf)
>>> generic.food.dish()
'Kartoffelklöße'
>>> generic.personal.full_name()
'Adie Jans'
kairichard commented 6 years ago

@lk-geimfari Needing to manually seed the concrete implementation requires modification to the code under test. Which in general is something I try to avoid.

lk-geimfari commented 6 years ago

@duckyou Can you advise anything, please?

duckyou commented 6 years ago

@kairichard If I understood correctly, you want use global seed for all providers (not like generic, where each new provider have its own seed). Unfortunately at this moment it is not supported. :pensive: But you can try use setUp or setUpClass

import unittest

from mimesis import Food

class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.cls_food = Food('en', seed='asd')

    def setUp(self):
        self.food = Food('en', seed='asd')

    def test_first_food_dish(self):
        print("test_first_food_dish:")
        print("setUpClass >>", self.cls_food.dish())
        print("setUp 1>>", self.food.dish())
        print("setUp 2>>", self.food.dish())

    def test_second_food_dish(self):
        print("test_second_food_dish:")
        print("setUpClass >>", self.cls_food.dish())
        print("setUp 1>>", self.food.dish())
        print("setUp 2>>", self.food.dish())

if __name__ == "__main__":
    unittest.main()

Output:

test_first_food_dish:
setUpClass >> Slinger
setUp 1>> Slinger
setUp 2>> Hummus
test_second_food_dish:
setUpClass >> Hummus
setUp 1>> Slinger
setUp 2>> Hummus
kairichard commented 6 years ago

@duckyou Thanks for effort you put into answering my question. Now I feel a bit ashamed noticing that my initial example is a bit misleading. I am using your awesome lib to produce names for things and I have an integration test that verify things get names. What I wanted to do is hardwire the test output. Something like this:

import unittest
import random

from service import App

class Test(unittest.TestCase):
    def test_names(self):
        result = App.create_thing()
        self.assertEqual(result.name, "ice-cream")

if __name__ == "__main__":
    random.seed("123")
    unittest.main()

HTH. What I am currently doing is seeding via os.env somewhere in service which is ok for now. Thanks again for answering my questions.