Writing a unittest - unit-testing

I am very new in python programming and trying to learn unittest currently.
I had wrote a program called Current_age.py and wanting to write a unittest for this, in which i don't know how. So please help me. Though i have given it a try but it does not work as i expected.
Current_age.py
import datetime
def age(birthday):
todays = datetime.date(2001, 5, 12)
yyyy = int(birthday[0:4])
mm = int(birthday[4:6])
dd = int(birthday[6:8])
date_of_birth = datetime.date(yyyy,mm,dd)
age_in_day = (todays - date_of_birth).days
age_in_years = round(age_in_day/365)
return age_in_years
And then i wrote a unittest file which called test_age
import unittest
import Current_age
class test_age(unittest.TestCase):
def Test_Learning_classes_age(self):
self.assertEqual(Current_age.age("20000315"), 1
if __name__ == "__main__":
unittest.main()
I use VS Code and had created a Virtual Environment and run the code straight on Vs Code because it is easier. So when i ran the code, it said
0 test ran in 0.00s
Ok
Please help me on this.
Hello there everyone, thank for commencing on the program.
I have try to rename some of the methods and classes with the files. And it work. But i really don't know where is the difference so if you can please help me spot it.
The first file is called Age.py which store the function.
import datetime
def age(birthday):
todays = datetime.date(2001, 5, 12)
yyyy = int(birthday[0:4])
mm = int(birthday[4:6])
dd = int(birthday[4:6]
date_of_birth = datetime.date(yyyy, mm, dd)
age_in_day = (todays - date_of_birth).days
age_in_years = round(age_in_day / 365)
return age_in_years
And then i created another file to test the function which called Testage.py
import Age
import unittest
class Testage(unittest.Testcase):
def test_age(self):
self.assertEqual(Age.age("19710113"), 30)
self.assertEqual(Age.age("20000712"), 1)
if __name__ == "__main__":
unittest.main()
And another question which is also related to unittest. Can i create a unittest that of a function which have user input()? And if it is possible how shall I do it? Thanks.

Improved and corrected version of your code:
from Age import age
import unittest
class TestAge(unittest.Testcase):
def test_age(self):
self.assertEqual(Age.age("19710113"), 30)
self.assertEqual(Age.age("20000712"), 1)
if __name__ == "__main__":
unittest.main()
And regarding your question, unit tests are not really designed to accept user input.

Related

__init__ variable not found in test class?

I recently changed from using nose to nose2, however a lot of my testing code seems to have broken in the process. One thing in particular is the init variable i put in my test class "self.mir_axis" is giving this error:
mirror_index = mirror_matrix.index(self.mir_axis)
AttributeError: 'TestConvert' object has no attribute 'mir_axis'
This used to work with nose, however with nose2 my init variable for some reason is no longer registering. Am I missing something here? Im using python 2.7.3, and eclipse as an IDE btw.
from nose2.compat import unittest
from nose2.tools import params
from nose2 import session
from nose2.events import ReportTestEvent
from nose2.plugins import testid
from nose2.tests._common import (FakeStartTestEvent, FakeLoadFromNameEvent,
FakeLoadFromNamesEvent, TestCase)#
# Import maya modules
import maya.cmds as mc
# Absolute imports of other modules
from neo_autorig.scripts.basic import name
from neo_autorig.scripts.basic import utils
# Test class for converting strings
class TestConvert(TestCase):
counter = 0 # counter to cycle through mir_axes
def _init__(self):
mir_axes = ['xy', '-xy', 'yz', '-yz'] # different axes to be applied
self.mir_axis = mir_axes[self.__class__.counter]
self.__class__.counter += 1 # increase counter when run
if self.__class__.counter > 3:
self.__class__.counter = 0 # if counter reaches max, reset
self.utils = utils.Utils(self.mir_axis, False) # pass module variables
def setUp(self): # set up maya scene
side_indicator_l = mc.spaceLocator(n='side_indicator_left')[0]
side_indicator_r = mc.spaceLocator(n='side_indicator_right')[0]
mirror_matrix = ['xy', '-xy', 'yz', '-yz']
trans_matrix = ['tz', 'tz', 'tx', 'tx']
side_matrix = [1, -1, 1, -1]
mirror_index = mirror_matrix.index(self.mir_axis)
mc.setAttr(side_indicator_l+'.'+trans_matrix[mirror_index], side_matrix[mirror_index])
mc.setAttr(side_indicator_r+'.'+trans_matrix[mirror_index], side_matrix[mirror_index]*-1)
def tearDown(self): # delete everything after
mc.delete('side_indicator_left', 'side_indicator_right')
def test_prefix_name_side_type(self): # test string
nc = name.Name('prefix_name_side_type')
existing = nc.get_scenenames('transform')
self.assertEqual(nc.convert('test', 'empty', self.utils.find_side('side_indicator_left'),
'object', existing), 'test_empty_l_object')
self.assertEqual(nc.convert('test', 'empty', self.utils.find_side('side_indicator_right'),
'object', existing), 'test_empty_r_object')
# run if script is run from inside module
if __name__ == '__main__':
import nose2
nose2.main()
I see two problems with the snippet you posted:
The first one is def _init__(self): is missing an underscore; it should be def __init__(self):
The second one (and seems to be the reason for the error) is the fact that the first line in _init__, mir_axes = ['xy', '-xy', ..., should be self.mir_axes = ...
Edit
You should use setUp instead of __init__ regardless, according to Ned Batchelder of Coverage.py fame. :)

making a function staticmethod in python is confusing

Hi I have a GUI written using Tkinter and the code template is as follows. My question is PyCharm gives me warnings on my functions (def func1, def func2) that they are static. To get rid of the warnings I placed #staticmethod above the functions. What does this do and is it necessary?
# Use TKinter for python 2, tkinter for python 3
import Tkinter as Tk
import ctypes
import numpy as np
import os, fnmatch
import tkFont
class MainWindow(Tk.Frame):
def __init__(self, parent):
Tk.Frame.__init__(self,parent)
self.parent = parent
self.parent.title('BandCad')
self.initialize()
#staticmethod
def si_units(self, string):
if string.endswith('M'):
num = float(string.replace('M', 'e6'))
elif string.endswith('K'):
num = float(string.replace('K', 'e3'))
elif string.endswith('k'):
num = float(string.replace('k', 'e3'))
else:
num = float(string)
return num
if __name__ == "__main__":
# main()
root = Tk.Tk()
app = MainWindow(root)
app.mainloop()
You can also turn off that inspection so that PyCharm doesn't warn you. Preferences -> Editor -> Inspections. Note that the inspection appears in the JavaScript section as well as the Python section.
You are right about #staticmethod being confusing. It is not really needed in Python code and in my opinion should almost never by used. Instead, since si_units is not a method, move it out of the class and remove the unused self parameter. (Actually, you should have done that when adding #staticmethod; the posted code will not work right with 'self' left in.)
Unless one has forgotten to use 'self' when it needs to be used, this is (or at least should be) the intent of the PyCharm warning. No confusion, no fiddling with PyCharm settings.
While you are at it, you could condense the function and make it easily extensible to other suffixes by using a dict.
def si_units(string):
d = {'k':'e3', 'K':'e3', 'M':'e6'}
end = string[-1]
if end in d:
string = string[:-1] + d[end]
return float(string)
for f in ('1.5', '1.5k', '1.5K', '1.5M'): print(si_units(f))

Selenium/Python Finding Element and Clicking it

I have been researching for a while about this and here is the code I wrote
driver = webdriver.Firefox()
time.sleep(10)
get("some website")
time.sleep(10)
x = driver.find_element_by_id("vB_Editor_QR_textarea")
x.click()
It keeps giving me error the part it's not working is getting the find_element and click()
It keeps giving me error from webdriver.py
here is the screen shot of the error note: i don't have a mouse at the moment so i just took a pic
https://gyazo.com/bc6f8d3e77f2e9d9b5bcbfe202b73258
You should try this:
driver = webdriver.Firefox()
driver.get("https://example.com") # Make sure you use double quotes
And instead of time.sleep() you should use implicit and explicit waits. I usually use an implicit wait.
driver.implicitly_wait(10) # 10 seconds
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available.
Try this simple google search automation:
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class AutoTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
def test_auto_test(self):
driver = self.driver
driver.get("http://www.google.com")
element = driver.find_element_by_css_selector('#lst-ib')
element.send_keys("StackOverflow")
element = driver.find_element_by_css_selector('#sblsbb > button > span').click()
if __name__ == "__main__":
unittest.main()

python problems with super

Ok so I'm having a bit of a problem with the code below. It works as is but if I try to change the part with the comment about me not being able to get super to work correctly to.
pipeline_class_call = super(Error_Popup,self)
broken_file_w_whats_wrong = pipeline_class_call.whats_wrong_with_file()
or to
broken_file_w_whats_wrong = super(Error_Popup,self).whats_wrong_with_file()
and change
class Error_Popup(QtGui.QDialog):
to
class Error_Popup(QtGui.QDialog,Pipeline_UI):
I get the following error
# TypeError: object of type 'instancemethod' has no len() #
Which normally means that I need to call the method, but doesn't super handle all this for me. Or am I goofing this?
from PySide import QtCore, QtGui
from shiboken import wrapInstance
import pymel.core as pm
import maya.OpenMayaUI as omui
from UI.UI import Pipeline_UI
def something_bad_happened_window():
sbh_pointer = omui.MQtUtil.mainWindow()
return wrapInstance(long(sbh_pointer), QtGui.QWidget)
class Error_Popup(QtGui.QDialog):
def __init__(self,parent=something_bad_happened_window()):
super(Error_Popup,self).__init__(parent)
self.setWindowTitle('Something Bad Happened!')
self.setWindowFlags(QtCore.Qt.Tool)
self.popup_layout()
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.connections()
def popup_layout(self):
self.file_description = QtGui.QListWidget()
#cant seem to get super to work appropriately... booo
pipeline_class_call = Pipeline_UI()
broken_file_w_whats_wrong = pipeline_class_call.whats_wrong_with_file()
for display in range(0,len(broken_file_w_whats_wrong)):
broken_list = QtGui.QListWidgetItem()
if display % 2 == 0:
broken_list.setText(broken_file_w_whats_wrong[display][0])
broken_list.asset = broken_file_w_whats_wrong[display][1]
else:
broken_list.setText(" " + broken_file_w_whats_wrong[display][0])
self.file_description.addItem(broken_file_w_whats_wrong[display])
self.import_button = QtGui.QPushButton('Import Replacement(s)')
error_layout = QtGui.QVBoxLayout()
error_layout.setContentsMargins(2,2,2,2)
error_layout.setSpacing(2)
error_layout.addWidget(self.file_description)
error_layout.addWidget(self.import_button)
error_layout.addStretch()
self.setLayout(error_layout)
def connections(self):
self.import_button.clicked.connect(Error_Popup.make_sphere)
#classmethod
def make_sphere(cls):
pm.polySphere()
def show_window():
ui = Error_Popup()
if __name__ == '__main__':
try:
ui.close()
except:
pass
ui.show()
show_window()
Thanks in advance everyone
Looks to me like it's a problem of using super with multiple inheritance. It picks one of the parents in a certain order to use. For example, super(Error_Popup,self).__init__(parent) only calls one of the parents __init__ methods. You have to manually call all of them.
When calling methods or accessing variables, you have to be specific about which parent you want to use or super will pick for you. See this answer and this answer.

Django test script to pre-populate DB

I'm trying to pre-populate the database with some test data for my Django project. Is there some easy way to do this with a script that's "outside" of Django?
Let's say I want to do this very simple task, creating 5 test users using the following code,
N = 10
i = 0
while i < N:
c = 'user' + str(i) + '#gmail.com'
u = lancer.models.CustomUser.objects.create_user(email=c, password="12345")
i = i + 1
The questions are,
WHERE do I put this test script file?
WHAT IMPORTS / COMMANDS do I need to put at the beginning of the file so it has access to all the Django environment & resources as if I were writing this inside the app?
I'm thinking you'd have to import and set up the settings file, and import the app's models, etc... but all my attempts have failed one way or another, so would appreciate some help =)
Thanks!
Providing another answer
The respondes below are excellent answers. I fiddled around and found an alternative way. I added the following to the top of the test data script,
from django.core.management import setup_environ
from project_lancer import settings
setup_environ(settings)
import lancer.models
Now my code above works.
I recommend you to use fixtures for these purposes:
https://docs.djangoproject.com/en/dev/howto/initial-data/
If you still want to use this initial code then read:
If you use south you can create migration and put this code there:
python manage.py schemamigration --empty my_data_migration
class Migration(SchemaMigration):
no_dry_run = False
def forwards(self, orm):
# more pythonic, you can also use bulk_insert here
for i in xrange(10):
email = "user{}#gmail.com".format(i)
u = orm.CustomUser.objects.create_user(email=email, password='12345)
You can put it to setUp method of your TestCase:
class MyTestCase(TestCase):
def setUp(self):
# more pythonic, you can also use bulk_insert here
for i in xrange(10):
email = "user{}#gmail.com".format(i)
u = lancer.models.CustomUser.objects.create_user(email=email,
password='12345')
def test_foo(self):
pass
Also you can define your BaseTestCase in which you override setUp method then you create your TestCase classes that inherit from BaseTestCase:
class BaseTestCase(TestCase):
def setUp(self):
'your initial logic here'
class MyFirstTestCase(BaseTestCase):
pase
class MySecondTestCase(BaseTestCase):
pase
But I think that fixtures is the best way:
class BaseTestCase(TestCase):
fixtures = ['users_for_test.json']
class MyFirstTestCase(BaseTestCase):
pase
class MySecondTestCase(BaseTestCase):
fixtures = ['special_users_for_only_this_test_case.json']
Updated:
python manage.py shell
from django.contrib.auth.hashers import make_password
make_password('12312312')
'pbkdf2_sha256$10000$9KQ15rVsxZ0t$xMEKUicxtRjfxHobZ7I9Lh56B6Pkw7K8cO0ow2qCKdc='
You can also use something like this or this to auto-populate your models for testing purposes.