pytest run the test in subprocess from within fixture - python-3.x

I have a fixture that wraps all of my tests, for example checking the GPU memory usage:
import pytest
import nvidia_smi
def gpu_memory_used():
nvidia_smi.nvmlInit()
device_count = nvidia_smi.nvmlDeviceGetCount()
assert device_count == 1, 'Should be 1 GPU'
handle = nvidia_smi.nvmlDeviceGetHandleByIndex(0)
info = nvidia_smi.nvmlDeviceGetMemoryInfo(handle)
used_memory = info.used
nvidia_smi.nvmlShutdown()
return used_memory
#pytest.fixture(autouse=True)
def check_gpu_memory():
memory_used_before_test = gpu_memory_used()
yield
memory_used_after_test = gpu_memory_used()
assert memory_used_after_test == memory_used_before_test
I'm wondering is it possible to run the yield in a subprocess and return the PASS/FAIL of the test to the fixture -> Important to note that I want the subprocess to be closed once done.
Thanks

Related

Assert whether a function is being called inside another function

I have 2 functions and the other one is called only when the parameter passed is True.
def func1(para1 = True):
// Some lines of code
if para1 == True:
func2()
def func2():
// Some lines of code
Now, I'm trying to create a unittest that checks whether the nested function func2 is being called(When parameter passed to func1 is true). I checked online and found something related to Mock() but did not understand how to use for this particular test case. How can I proceed with this?
example.py:
def func1(para1=True):
if para1 == True:
func2()
def func2():
pass
test_example.py:
from unittest import TestCase
import unittest
from unittest.mock import patch
from example import func1
class TestExample(TestCase):
#patch('example.func2')
def test_func1__should_call_func2(self, mock_func2):
func1()
mock_func2.assert_called_once()
#patch('example.func2')
def test_func1__should_not_call_func2(self, mock_func2):
func1(False)
mock_func2.assert_not_called()
if __name__ == '__main__':
unittest.main()
Test result:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK

Unit testing in Python: Nesting mocked objects

I am new to unit testing in Python. I am trying to unit test a method that does something like this:
MyClass:
client : Client
def __init__(client):
self.client=client
def method_to_test(self):
images = self.client.get_stuff()
image = images[0]
result = []
for region in image.regions:
result.append(region.region_id)
return result
I have tried mocking and nesting of all the classes involved: Client, Image and ImageRegion. But at some point the mocking breaks down and my test fails. Is there a way to mock things so that one can do something like:
def test_method_to_test():
result = MyClass(mock_client).method_to_test()
assert dummy_region_id in result
... or perhaps better ways to test in such situations with nested custom objects?
My latest attempt looks like this:
with patch('package.module.ImageRegion') as MockRegion:
region = MockRegion()
region.region_id.return_value = dummy_region_id
with patch('package.module.Image') as MockImage:
image = MockImage()
image.regions.return_value = [region]
with patch('package.module.Client') as MockClient:
mock_client = MockClient()
mock_client.get_regions.return_value = [image]
result = MyClass(mock_client).method_to_test()
assert dummy_region_id in result
You could create mocked object using unittest.mock and use Dependency Injection to pass the mocked object to MyClass.
E.g.
myclass.py:
class MyClass:
def __init__(self, client):
self.client = client
def method_to_test(self):
images = self.client.get_stuff()
image = images[0]
result = []
for region in image.regions:
result.append(region.region_id)
return result
test_myclass.py:
import unittest
from unittest.mock import Mock
from collections import namedtuple
from myclass_63948475 import MyClass
Image = namedtuple('Image', ['regions'])
Region = namedtuple('Region', 'region_id')
class TestMyClass(unittest.TestCase):
def test_method_to_test(self):
regions = [Region('1'), Region('2'), Region('3')]
images = [Image(regions=regions)]
mock_client = Mock()
mock_client.get_stuff.return_value = images
myclass = MyClass(mock_client)
actual = myclass.method_to_test()
mock_client.get_stuff.assert_called_once()
self.assertEqual(actual, ['1', '2', '3'])
if __name__ == '__main__':
unittest.main()
unit test result with coverage report:
coverage run /Users/ldu020/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/63948475/test_myclass_63948475.py && coverage report -m
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------------
src/stackoverflow/63948475/myclass_63948475.py 10 0 100%
src/stackoverflow/63948475/test_myclass_63948475.py 18 0 100%
-----------------------------------------------------------------------------------
TOTAL 28 0 100%

how to write a unittest for a class?

class Hand:
def __init__(self,cards, total, soft_ace_count):
self.cards = cards
self.total = total
self.soft_ace_count = soft_ace_count
def __str__(self):
return(str(self.cards)+','+str(self.total)+','+str(self.soft_ace_count))
def add_card(self):
self.cards.append(get_card())
self.score()
def is_blackjack(self):
return len(self.cards)==2 and self.total==21
def is_bust(self):
return self.total > 21
def score(self):
self.total=0
self.soft_ace_count=0
for x in self.cards:
if x > 10:
x=10
self.total+=x
#the following code will decide 1 =11 or 1 = 1
if self.total <= 11 and 1 in self.cards:
self.total+=10
self.soft_ace_count+=1
I am trying to write the unittest for this 'Hand' class. Do I need a init setup for this particular unittest?
Here is part of code of my unittest. Thank you so much if anyone could help me with this. I just started in python. Any suggestions would help. Thank you. Neglect the indent
class hand(unittest.TestCase):
def __init__(self):
self.cards=cards
self.total = total
self.soft_ace_count = soft_ace_count
Assuming that you have your class in a module named hand.py, you can place your unittest script in the same directory. It could look like this:
import unittest
from hand import Hand
class hand(unittest.TestCase):
def test_init(self):
cards = []
h = Hand(cards, 0, 0)
self.assertEqual(h.total, 0)
self.assertEqual(h.soft_ace_count, 0)
self.assertEqual(len(h.cards), 0)
# def test_blackjack(self):
#....
# def test_score(self):
#....
# def test_OTHERTHINGS(self):
#.....
if __name__ == '__main__':
unittest.main()
if you name your unittestscript for example unittesthand.py, you can run it via "python unittestscript.py". You will get the following result:
> .
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
The unittest component has executed all methods starting with "test" and executed. In the example the "test_init" method. This is NOT the initialization of the test, but the unittest for the initialization of class Hand.
Now change for example the code to "self.assertEqual(h.total, 1)", and you will see that the unittest component reports an error.
Now you can create additional cases for the other methods.You can also create a base test case with code that is always executed before and after the unittests and so on...

unit test in python for function that has no return value

I have a function that should pick only top 10 requests from list of requests:
def prioritize_top_10_requests(list_of_requests):
if not list_of_requests:
system.exit(1)
else:
for i in list_of_requests[0:10]:
print i
I want to write a unit test for this function just to check if 'i' is printed 10 times only though we have more list of requests.
I am writing python unit test cases for the first time.
I don't have python3 set up. The below code works with Python 3.
What it does is the following.
Created a UnitTest TestCase with one test, "test_priority".
In the test, redirect the stdout to a string.
Then execute the function.
Collect the print results from the string.
Remove None and empty strings and find the length.
Check if it is equal to 10.
import unittest
from io import StringIO
import sys
def prioritize_top_10_requests(list_of_requests):
for i in list_of_requests[0:10]:
print(i)
class TestMyCode(unittest.TestCase):
def test_priority(self):
sys.stdout = result = StringIO()
prioritize_top_10_requests(range(100))
sys.stdout = sys.__stdout__
printed_lines = result.getvalue()
print_count = len(printed_lines.strip().split('\n'))
self.assertEqual(print_count, 10)
if __name__ == '__main__':
unittest.main()

How to decorate an asyncio.coroutine to retain its __name__?

I've tried to write a decorator function which wraps an asyncio.coroutine and returns the time it took to get done. The recipe below contains the code which is working as I expected. My only problem with it that somehow I loose the name of the decorated function despite the use of #functools.wraps. How to retain the name of the original coroutine? I checked the source of asyncio.
import asyncio
import functools
import random
import time
MULTIPLIER = 5
def time_resulted(coro):
#functools.wraps(coro)
#asyncio.coroutine
def wrapper(*args, **kargs):
time_before = time.time()
result = yield from coro(*args, **kargs)
if result is not None:
raise TypeError('time resulted coroutine can '
'only return None')
return time_before, time.time()
print('= wrapper.__name__: {!r} ='.format(wrapper.__name__))
return wrapper
#time_resulted
#asyncio.coroutine
def random_sleep():
sleep_time = random.random() * MULTIPLIER
print('{} -> {}'.format(time.time(), sleep_time))
yield from asyncio.sleep(sleep_time)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
tasks = [asyncio.Task(random_sleep()) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
for task in tasks:
print(task, task.result()[1] - task.result()[0])
print('= random_sleep.__name__: {!r} ='.format(
random_sleep.__name__))
print('= random_sleep().__name__: {!r} ='.format(
random_sleep().__name__))
The result:
= wrapper.__name__: 'random_sleep' =
1397226479.00875 -> 4.261069174838891
1397226479.00875 -> 0.6596335046471768
1397226479.00875 -> 3.83421163259601
1397226479.00875 -> 2.5514027672929713
1397226479.00875 -> 4.497471439365472
Task(<wrapper>)<result=(1397226479.00875, 1397226483.274884)> 4.266134023666382
Task(<wrapper>)<result=(1397226479.00875, 1397226479.6697)> 0.6609499454498291
Task(<wrapper>)<result=(1397226479.00875, 1397226482.844265)> 3.835515022277832
Task(<wrapper>)<result=(1397226479.00875, 1397226481.562422)> 2.5536720752716064
Task(<wrapper>)<result=(1397226479.00875, 1397226483.51523)> 4.506479978561401
= random_sleep.__name__: 'random_sleep' =
= random_sleep().__name__: 'wrapper' =
As you can see random_sleep() returns a generator object with different name. I would like to retain the name of the decorated coroutine. I am not aware if this is problem is specific to asyncio.coroutines or not. I also tried the code with different decorator orders, but all has the same result. If I comment #functools.wraps(coro) then even random_sleep.__name__ becomes wrapper as I expected.
EDIT: I've posted this issue to Python Issue Tracker and received the following answer by R. David Murray: "I think this is a specific case of a more general need to improve 'wraps' that was discussed on python-dev not too long ago."
The issue is that functools.wraps changes only wrapper.__name__ and wrapper().__name__ stays wrapper. __name__ is a readonly generator attribute. You could use exec to set appropriate name:
import asyncio
import functools
import uuid
from textwrap import dedent
def wrap_coroutine(coro, name_prefix='__' + uuid.uuid4().hex):
"""Like functools.wraps but preserves coroutine names."""
# attribute __name__ is not writable for a generator, set it dynamically
namespace = {
# use name_prefix to avoid an accidental name conflict
name_prefix + 'coro': coro,
name_prefix + 'functools': functools,
name_prefix + 'asyncio': asyncio,
}
exec(dedent('''
def {0}decorator({0}wrapper_coro):
#{0}functools.wraps({0}coro)
#{0}asyncio.coroutine
def {wrapper_name}(*{0}args, **{0}kwargs):
{0}result = yield from {0}wrapper_coro(*{0}args, **{0}kwargs)
return {0}result
return {wrapper_name}
''').format(name_prefix, wrapper_name=coro.__name__), namespace)
return namespace[name_prefix + 'decorator']
Usage:
def time_resulted(coro):
#wrap_coroutine(coro)
def wrapper(*args, **kargs):
# ...
return wrapper
It works but there is probably a better way than using exec().
In the time since this question was asked, it became possible to change the name of a coroutine. It is done by setting __qualname__ (not __name__):
async def my_coro(): pass
c = my_coro()
print(repr(c))
# <coroutine object my_coro at 0x7ff8a7d52bc0>
c.__qualname__ = 'flimflam'
print(repr(c))
# <coroutine object flimflam at 0x7ff8a7d52bc0>
import asyncio
print(repr(asyncio.ensure_future(c)))
# <Task pending name='Task-737' coro=<flimflam() running at <ipython-input>:1>>
The usage of __qualname__ in a coroutine object's __repr__ is defined in the CPython source

Resources