Is it possible to get string from function?

Steven D'Aprano steve at pearwood.info
Thu Jan 16 02:16:29 EST 2014


On Wed, 15 Jan 2014 22:46:54 -0500, Roy Smith wrote:

> I've got some unit tests that look like:
> 
> class Foo(TestCase):
>   def test_t1(self):
>     RECEIPT = "some string"
> 
>   def test_t2(self):
>     RECEIPT = "some other string"
> 
>   def test_t3(self):
>     RECEIPT = "yet a third string"
> 
> and so on.  It's important that the strings be mutually unique.  In the
> example above, it's trivial to look at them and observe that they're all
> different, but in real life, the strings are about 2500 characters long,
> hex-encoded.  It even turns out that a couple of the strings are
> identical in the first 1000 or so characters, so it's not trivial to do
> by visual inspection.

Is the mapping of receipt string to test fixed? That is, is it important 
that test_t1 *always* runs with "some string", test_t2 "some other 
string", and so forth?

If not, I'd start by pushing all those strings into a global list (or 
possible a class attribute. Then:

LIST_OF_GIANT_STRINGS = [blah blah blah]  # Read it from a file perhaps?
assert len(LIST_OF_GIANT_STRINGS) == len(set(LIST_OF_GIANT_STRINGS))


Then, change each test case to:

    def test_t1(self):
        RECEIPT = random.choose(LIST_OF_GIANT_STRINGS)


Even if two tests happen to pick the same string on this run, they are 
unlikely to pick the same string on the next run.

If that's not good enough, if the strings *must* be unique, you can use a 
helper like this:

def choose_without_replacement(alist):
    random.shuffle(alist)
    return alist.pop()

class Foo(TestCase):
    def test_t1(self):
        RECEIPT = choose_without_replacement(LIST_OF_GIANT_STRINGS)


All this assumes that you don't care which giant string matches which 
test method. If you do, then:

DICT_OF_GIANT_STRINGS = {
    'test_t1': ..., 
    'test_t2': ..., 
    }  # Again, maybe read them from a file.

assert len(list(DICT_OF_GIANT_STRINGS.values())) == \
       len(set(DICT_OF_GIANT_STRINGS.values()))


You can probably build up the dict from the test class by inspection, 
e.g.:

DICT_OF_GIANT_STRINGS = {}
for name in Foo.__dict__:
    if name.startswith("test_"):
        key = name[5:]
        if key.startswith("t"):
            DICT_OF_GIANT_STRINGS[name] = get_giant_string(key)

I'm sure you get the picture. Then each method just needs to know it's 
own name:


class Foo(TestCase):
    def test_t1(self):
        RECEIPT = DICT_OF_GIANT_STRINGS["test_t1"]


which I must admit is much easier to read than 

        RECEIPT = "...2500 hex encoded characters..."


-- 
Steven



More information about the Python-list mailing list