In pytest returns magicMock instance instead of return value - unit-testing

i have a sample method and a pytest method for it.
import pytest
from datetime import datetime
# this is the method to test
def get_time_of_day():
"""return string Night/Morning/Afternoon/Evening depending on the hours range"""
time = datetime.now()
print(time.hour)
if 0 <= time.hour <6:
return "Night"
if 6 <= time.hour < 12:
return "Morning"
if 12 <= time.hour <18:
return "Afternoon"
return "Evening"
#pytest method, where I am trying to mock datetime.now
def test_get_time_of_day(mocker):
mock_now = mocker.patch("tests.test_sample.datetime")
mock_now.now.return_value = datetime(2016, 5, 20, 14, 10, 0)
assert get_time_of_day() == "Afternoon"
But when I try to run the pytest as follow
python3 -m pytest test_sample.py
I get TypeError: '<=' not supported between instances of 'int' and 'MagicMock'
I have a directory tests inside that I have the python file test_sample.py. In this file, I have written this code.
I have referred this page:
So do anyone Know to solve this issue. Thank you

This is because when you are assigning a value to mock_now.now.return_value, datetime is already patched and returns a MagicMock instead of the datetime object as you expect.
This would work:
def test_get_time_of_day(mocker):
dt = datetime(2016, 5, 20, 14, 10, 0)
mock_now = mocker.patch("tests.test_sample.datetime")
mock_now.now.return_value = dt
assert get_time_of_day() == "Afternoon"
As you would typically patch objects in modules that you test (instead of within the test module itself), you would not run into this issue.

Related

I'm struggling to create a unit test, if someone could please have a look on my code to figure out the possible issue:

The code below is supposed to simulate a ATM, I have to create 5 unit tests for the code, and to be honest I have no idea why it is not working! :(
It should show on the Terminal that ran 5 tests in x s, however it keeps saying that Ran 0 tests and OK. Should I import a library? Any suggestion?
import unittest
def withdraw(wdra):
balanace_account = 100
if wdra < balanace_account:
balanace_account -= wdra
return balanace_account
class AtmTest(unittest.TestCase):
def correct_amount(self):
expected = 29.50 #withdraw de 70.50
result = withdraw(70.5)
self.assertEqual(expected,result)
def invalid_error(self):
expected = 1
result = withdraw(1/0)
self.assertEqual(expected, result)
def incorrect_amount(self):
expected = 50.00
result = withdraw(60)
self.assertEqual(expected,result)
def greater_withdraw(self):
expected = -10
result = withdraw(110)
self.assertEqual(expected,result)
def invalid_data_type(selfS):
expected = 100
result = withdraw('0')
self.assertEqual(expected, result)
if __name__ == '__main__':
unittest.main()
pass
You should name your test methods with test prefix so that the test runner can identify test methods. See here for example.

How I can invoke importing class in other class Python

#!/usr/bin/env python
from __future__ import print_function
import sys
import time
import getopt
import alsaaudio
import numpy
from time import sleep
class A_weight():
def __init__(self):
skaler = 2.361E-14
fix_cur = 0.20565360419770495
A = []
hPa = 4e-11
card = 'default'
array_float = numpy.dtype(float)
stream = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, card)
stream.setchannels(1)
stream.setrate(48000)
stream.setformat(alsaaudio.PCM_FORMAT_S16_LE)
stream.setperiodsize(128)
def A(f):
return (12200**2*f**4/((f**2+20.6**2)*(f**2+12200**2)*numpy.sqrt(f**2+107.7**2)*numpy.sqrt(f**2+737.9**2)))+fix_cur
def listen(self):
glob_leq = 0
liczba_ramek = 0
index_ramek = 0
while True:
try:
l, data = stream.read()
except IOError, e:
error_count += 1
print(" (%d) Error recording: %s" % (error_count, e))
else:
if l==128:
decoded_block = numpy.frombuffer(data, dtype='int16' )
else:
continue
Y = numpy.fft.fft(decoded_block) # fft computing and normalization
Aw = A(numpy.arange(20.,20000,(19980./len(Y))))
Na = Aw*Y
inverse = numpy.fft.ifft(Y)
maks = 32768
array_float = numpy.divide(inverse.real ,float( maks))
array_float = array_float**2
sum_array = numpy.sum(array_float, dtype=float)
glob_leq = glob_leq + sum_array
liczba_ramek += 1
index_ramek += 1
if index_ramek == 375:
index_ramek=0
cis_chwil = numpy.divide(glob_leq, liczba_ramek * 128)
leq =10*numpy.log10(numpy.divide(cis_chwil, hPa))
print (leq)
#A.append(leq)
#print(max(A))
A_weight().listen()
So i trying writing program compute sound pressure level with weighting A.
All work correct but when i want close may code in class I have problem. Because something wrong with invoke to importing class in this case is it alsaaudio.
I get this feedback:
Traceback (most recent call last):
File "rec_A.py", line 64, in <module>
A_weight().listen()
File "rec_A.py", line 37, in listen
l, data = stream.read()
NameError: global name 'stream' is not defined
Do you have any idea
Change each occurrence of stream to self.stream:
class A_weight():
def __init__(self):
skaler = 2.361E-14
fix_cur = 0.20565360419770495
A = []
hPa = 4e-11
card = 'default'
array_float = numpy.dtype(float)
self.stream = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, card)
self.stream.setchannels(1)
self.stream.setrate(48000)
self.stream.setformat(alsaaudio.PCM_FORMAT_S16_LE)
self.stream.setperiodsize(128)
...
def listen(self):
glob_leq = 0
liczba_ramek = 0
index_ramek = 0
while True:
try:
l, data = self.stream.read()
...
This will make it an instance variable, and all other methods of that class (as long as they are passed the self argument) will have access to it through self.stream. See this bit of documentation for more details on instance variables.
Also, this is merely an aesthetic point, but the convention in Python is to use upper camel case for class names, i.e., AWeight instead of A_weight - but this will not affect how your code runs.

Python: Mock Opening File, return Actual File

I need to test a call to gzip.open, but I need it to supply it with an actual test file with test data in it to read. I've seen several very similar questions, but none of them work as expected.
This is the code I'm testing:
with gzip.open(local_file_path,'r') as content:
for line in content:
try:
if line.startswith('#'):
continue
line_data = line.split('\t')
request_key = line_data[LINE_FORMAT['date']]
request_key += '-' + line_data[LINE_FORMAT['time']][:-3]
request_key += '-' + line_data[LINE_FORMAT['source_ip']]
if request_key in result.keys():
result[request_key] += 1
else:
result[request_key] = 1
num_requests += 1
except Exception, e:
print ("[get_outstanding_requesters] \t\tError to process line: %s"%line)
I think the problem is related to the issues discussed here because the code treats the file as an iterator, but none of the workarounds discussed have worked for me.
I've tried variations on this:
test_data = open('test_access_log').read()
m = mock.mock_open(read_data=test_data)
m.return_value.__iter__ = lambda self:self
m.return_value.__next__ = lambda self: self.readline()
with mock.patch('gzip.open', m):
with gzip.open('asdf') as f:
for i in f:
print i
Which results in:
TypeError: iter() returned non-iterator of type 'MagicMock'
I'm using Python 2.7. I'm tearing my hair out over this one. Is my only solution to forget trying to use an iterator (actual files can be very large, which is why I'm trying to avoid doing so?)
This is working:
import unittest
import mock
test_data = open('test_access_log').read()
m = mock.mock_open(read_data=test_data)
m.return_value.__iter__.return_value = test_data.splitlines()
with mock.patch('gzip.open', m):
with gzip.open('test_access_log') as f:
for i in f:
print i
Thanks to bash-shell.net

Python KeyError: 1.0

I'm trying to run this code
from math import sqrt
import numpy as np
import warnings
from collections import Counter
import pandas as pd
import random
def k_nearest_neighbors(data,predict, k =3):
if len(data) >= k:
warnings.warn('K is set to a value less than total voting groups')
distances = []
for group in data:
for features in data[group]:
eucliden_distance = np.linalg.norm(np.array(features)-np.array(predict))
distances.append([eucliden_distance,group])
votes = [i[1] for i in sorted(distances)[:k]]
print(Counter(votes).most_common(1))
vote_result = Counter(votes).most_common(1)[0][0]
return vote_result
df = pd.read_csv('bc2.txt')
df.replace('?',-99999,inplace=True)
df.drop(['id'],1,inplace = True)
full_data = df.astype(float).values.tolist()
random.shuffle(full_data)
test_size = 0.2
train_set = {2:[],4:[]}
test_set = {2:[],4:[]}
train_data = full_data[:-int(test_size*len(full_data))]
test_data = full_data[-int(test_size*len(full_data)):]
for i in train_data:
train_set[i[-1]].append(i[:-1])
for i in train_data:
test_set[i[-1]].append(i[:-1])
correct = 0
total = 0
for group in test_set:
for data in test_set[group]:
vote = k_nearest_neighbors(train_set,data, k=5)
if group == vote:
correct += 1
total += 1
print ('Accuracy:',correct/total)
it comes out with this error msg
File "ml8.py", line 38, in <module>
train_set[i[-1]].append(i[:-1])
KeyError: 1.0
file m18.py is this above code file
below is the sample of txt file
id,clump_thickness,unif_cell_size,unif_cell_shape,marg_adhesion,single_epith_cell_size,bare_nuclei,bland_chrom,norm_nucleoli,mitoses,class
1000025,2,5,1,1,1,2,1,3,1,1
1002945,2,5,4,4,5,7,10,3,2,1
1015425,2,3,1,1,1,2,2,3,1,1
1016277,2,6,8,8,1,3,4,3,7,1
1017023,2,4,1,1,3,2,1,3,1,1
1017122,4,8,10,10,8,7,10,9,7,1
1018099,2,1,1,1,1,2,10,3,1,1
1018561,2,2,1,2,1,2,1,3,1,1
1033078,2,2,1,1,1,2,1,1,1,5
1033078,2,4,2,1,1,2,1,2,1,1
1035283,2,1,1,1,1,1,1,3,1,1
1036172,2,2,1,1,1,2,1,2,1,1
1041801,4,5,3,3,3,2,3,4,4,1
I'm using 2.7.11 version
Your train_set only contains keys 2 and 4, whereas your classes in that sample are 1 and 5.
Instead of using
train_set = {2:[],4:[]}
you might have better luck with defaultdict:
from collections import defaultdict
train_set = defaultdict(list)
This way a non-existent key will be initialized to a new empty list on first access.

How to get direct return value instead of <MagicMock name='mock.xx' id='yy'>

This is my testing code :
import mock
import unittest
def check_method_return(input):
return_value = input.ops.list()
if not return_value:
return False
return return_value
def check_method_len(input):
return_value = input.ops.list()
if len(return_value) < 1:
return False
return return_value
class TestMockReturnValue(unittest.TestCase):
def test_mock_return(self):
fake_input = mock.MagicMock()
fake_input().ops.list.return_value = []
result = check_method_return(fake_input)
self.assertFalse(result)
def test_mock_len(self):
fake_input = mock.MagicMock()
fake_input().ops.list.return_value = []
result = check_method_len(fake_input)
self.assertFalse(result)
if __name__ == '__main__':
test_empty = []
if not test_empty:
print("empty list equals to False")
unittest.main()
The run result output is :
empty list equals to False
.F
======================================================================
FAIL: test_mock_return (__main__.TestMockReturnValue)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_mock.py", line 31, in test_mock_return
self.assertFalse(result)
AssertionError: <MagicMock name='mock.ops.list()' id='140459969939728'> is not false
----------------------------------------------------------------------
Ran 2 tests in 0.005s
FAILED (failures=1)
Because when the list is empty, its return value for if is False. So, method "check_method_return" should work exactly the same as "check_method_len" in the real world.
So, my question is :
Is there a way to make the unit test pass for "check_method_return" ?
If this is the case, Here is the solution, I cannot explain the exact difference, but it makes sense:
# this mock away input.ops.list()
fake_input.ops.list.return_value = []
# this did not mock away input.ops.list()
fake_input().ops.list.return_value = []
To show the difference between 2 ways to set mock_input return value
This could help to understand better
[gliang#www ~]$ ipython
Python 2.6.6 (r266:84292, Jul 23 2015, 15:22:56)
IPython 0.13.2 -- An enhanced Interactive Python.
In [1]: import unittest
In [2]: import mock
In [3]: fake_input mock.Mag
mock.MagicMixin mock.MagicMock mock.MagicProxy
In [4]: fake_input = mock.MagicMock()
In [5]: fake_input().ops.list.return_value= []
In [6]: print fake_input().ops.list.return_value
[]
In [7]: print fake_input.ops.list.return_value
<MagicMock name='mock.ops.list()' id='15160848'>
In [8]: fake_input2 = mock.MagicMock()
In [9]: fake_input2.ops.list.return_value = []
In [10]: print fake_input2.ops.list.return_value
[]
In [11]: quit()