Happy Account
Happy Account

Reputation: 53

How to dynamically create parameterized test from the file (json or yaml) in python

Really need an advice how to dynamically create parameterized tests from the file (json or yaml) in python. File contains list of urls

file example :

 { "name":"url_1", "url":"http://check.com","expected": "23"}

or :

{ "url_1", "http://check.com","23"}

Example like this:

@parameterized(from the file import name, expected)

def testUrl (self, name, url, expected):
    run something (%s) url
    assertTrue( expected = result)

OUTPUT :

test_for_url_1_ (test.TestClass) ... ok
test_for_url_2_ (test.TestClass) ... ok

I'm checking nose-parameterized for:

# An iterable of params
@parameterized(
    param.explicit(*json.loads(line))
    for line in open("testcases.jsons")
)
def test_from_json_file(...):
    ...

But can't make it work :(

Thank you in advance

Upvotes: 3

Views: 2634

Answers (1)

Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39606

In case you just want to pass params from file to single function:

Yes, you can use decorator, pass filename to it, load json from file and use as decorated func's params:

import json
from functools import wraps


def params_from_file(file):
    """Decorator to load params from json file."""
    def decorator(func_to_decorate):
        @wraps(func_to_decorate)
        def wrapper(self, *args, **kwargs):
            with open(file, 'r') as fh:
                kwargs = json.loads(fh.read())
                return func_to_decorate(self, **kwargs)
        return wrapper
    return decorator

Usage:

import unittest


class Test(unittest.TestCase):
    @params_from_file('file.txt')  # {"name":"url_1", "url":"http://check.com", "expected": "23"}
    def test_url(self, name, url, expected):        
        self.assertEqual(name, 'url_1')
        self.assertEqual(url, 'http://check.com')
        self.assertEqual(expected, '23')
        # print(name, url, expected)


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

In case you want to create multiple new tests from params set:

import json


def create_tests(func_name, file):
    def decorator(cls):
        func = getattr(cls, func_name)
        # Set new funcs to class:
        with open(file, 'r') as fh:
            data = json.loads(fh.read())['data']
            for i, params in enumerate(data):
                def tmp(params=params):  # need for http://stackoverflow.com/q/7546285/1113207
                    def wrapper(self, *args, **kwargs):
                        return func(self, **params)      
                    return wrapper          
                setattr(cls, func_name + '_' + str(i), tmp())
        # Remove func from class:
        setattr(cls, func_name, None)
        return cls
    return decorator

Usage:

import unittest


@create_tests('test_url', 'file.txt')
class Test(unittest.TestCase):
    def test_url(self, name, url, expected):
        print(name, url, expected)


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

Output:

test_url_0 (__main__.Test) ... name1 https://example.com 175
ok
test_url_1 (__main__.Test) ... name2 https://example2.com 15
ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

Upvotes: 2

Related Questions