pip install -U pytest
(Aptana = Windows -> Preferences -> PyDev -> PyUnit ->
Test Runner = Py.test runner AND Show the results in the unittest results view)
(Pycharm -> File -> Settings -> Python Integrated Tools -> Default test runner (py.test))
(To avoid unnecessary red squiggly lines from imports...)
Pycharm -> File -> Settings -> Project Structure -> Add Content (right click Sources)
1. add source (for dependency libraries): File -> Settings -> Project Structure
2. verbose and display stdout: Run -> Configurations -> Defaults -> Python tests -> py.test -> Options: -v -s
3. Google App Engine libraries: File -> Settings -> (Project Settings[your-project]) -> Google App Engine -> Enable Google App Engine Support (browse to the installed library)
PYCHARM TIPS:
F2 to find the next error
File -> Settings (or DefaultSettings) -> search for pep (turn off pep8 violations)
File -> Settings (or DefaultSettings) -> search for spelling (turn off spelling violations)
Control + Alt + L = Apply Style Formatting (Settings or DefaultSettings -> Python Style)
File -> Settings -> Project Interpeter -> Python Interpreters (e.g. + C:/Python27/python.exe)
Packages -> Install (pycrypto, M2Crypto, pytest, WebOb, requests, etc.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
main.py
def number( number ):
if number == 0:
name = 'zero'
else:
name = 'no input'
return name
if __name__ == '__main__':
print number( 0 )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# pytest custom error message validation (i.e. assert 'MyErr:' in str(excinfo) or assert excinfo.value.message == 'oh no!' )
def test_get_upload_url_when_already_committed_gets_an_error( self, controller , testfile ):
# Given
parameters = { 'size': testfile.size , 'hash': testfile.hashValue, 'callerIP': 'localhost' }
controller.get_upload_url( parameters )
controller.commit_blob( { 'size': str( testfile.size ) , 'hash': testfile.hashValue } )
with pytest.raises( RuleException ) as excinfo:
controller.get_upload_url( parameters )
print type( excinfo.value.errorNumber ), type( Err.ALREADY_DONE.errorNumber )
assert excinfo.value.errorNumber == Err.ALREADY_DONE.errorNumber
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# pytest parameterization and test function arguments
# py.test pytest-parameterization.py
def pytest_generate_tests(metafunc):
if "numiter" in metafunc.funcargnames:
metafunc.parametrize("numiter", range(10))
def test_func(numiter):
assert numiter < 9
def pytest_funcarg__myfuncarg( request ):
return 42
def test_function( myfuncarg ):
assert myfuncarg == 17
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pytest.sh
#!/bin/sh
REPO_HOME=..
export REPO_HOME
REQUESTS_LIB=${REPO_HOME}/oxygenclient/lib/requests-1.2.0-py2.7.egg
export REQUESTS_LIB
PYTHONPATH=${REQUESTS_LIB}
export PYTHONPATH
GAE_HOME=/usr/local/google_appengine
export GAE_HOME
GAE_WEBAPP2=`ls -dt1 ${GAE_HOME}/lib/webapp2* | head -n1`
export GAE_WEBAPP2
GAE_JINJA2=`ls -dt1 ${GAE_HOME}/lib/jinja2* | head -n1`
export GAE_WEBAPP2
PYTHONPATH=${GAE_HOME}:${GAE_HOME}/lib/yaml/lib:${GAE_HOME}/lib/antlr3:${GAE_HOME}/lib/simplejson:${GAE_HOME}/lib/fancy_urllib:${GAE_WEBAPP2}:${GAE_HOME}/lib/django_1_4:${GAE_JINJA2}:${REPO_HOME}/AppEngine2:${REQUESTS_LIB}
export PYTHONPATH
py.test $*
# py.test $* -s -v -k number # view the print statements, the verbose testname and result, and only tests whose name contains "number"
py.test -x # recurse directory and subdirs and stop on first failure, or --maxfail=3
# collection starts from the initial command line arguments which may be directories, filenames or test ids.
# recurse into directories, unless they match norecursedirs
# test_*.py or *_test.py files, imported by their package name.
# Test prefixed test classes (without an __init__ method)
# test_ prefixed test functions or methods are test items
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
main_test.py
import main
def test_number():
assert main.number( 0 ) == 'zero'
run using py.test in the directory containing main.py and main_test.py
OR py.test main_test.py
EXPECTED OUTPUT
py.test main_test.py
==================================================================== test session starts ===
latform win32 -- Python 2.7.3 -- pytest-2.3.4
ollected 1 items
ain_test.py .
================================================================= 1 passed in 0.03 seconds =
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# more complicated example of imports - USE THE UNIVERSAL PATH DETECTION LINE BELOW
import sys
import os
sys.path.append( os.path.join( os.path.dirname(__file__), 'lib' ) )
import o2lib
import o2exceptions
import MultipartPostHandler
# from lib.MultipartPostHandler import MultipartPostHandler
def number( number ):
agent = o2lib.OxygenAdapter( 'api_key' , 'account_setup.py' , 'https://api.n2ocloud.com/gateway' )
example = MultipartPostHandler.MultipartPostHandler()
if number == 0:
name = 'zero'
else:
name = 'no input'
return name
if __name__ == '__main__':
print number( 0 )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Super complicated hack way to get GAE testing framework to work...
# -*- coding: utf-8 -*-
import pytest
from google.appengine.ext import testbed # Make sure GAE libraries are in your PYTHONPATH , https://developers.google.com/appengine/docs/python/tools/localunittesting
from google.appengine.ext.webapp import Request, Response # Make sure GAE libraries are in your PYTHONPATH
# Huge hack to override google app engine test framework not initializing correctly
APP_ID = 'myapp'
import os
os.environ['APPLICATION_ID'] = APP_ID
from google.appengine.api import apiproxy_stub_map,datastore_file_stub
from google.appengine.api.memcache import memcache_stub
apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
stub = datastore_file_stub.DatastoreFileStub( APP_ID, datastore_file=None )
apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub )
apiproxy_stub_map.apiproxy.RegisterStub('memcache', memcache_stub.MemcacheServiceStub())
class AppEngineFixture():
def __init__(self, request):
self.setup(request)
def setup(self, request):
self.test_env = testbed.Testbed()
self.test_env.activate()
self.test_env.init_datastore_v3_stub()
self.test_env.init_taskqueue_stub(True)
self.test_env.init_memcache_stub()
self.test_env.init_user_stub()
self.test_env.init_app_identity_stub(enable=True)
# self.test_env.init_all_stubs( enable=True)
request.addfinalizer(self.teardown)
def teardown(self):
self.test_env.deactivate()
@pytest.fixture
def mock_gae(request):
return AppEngineFixture(request)
def create_mock_request():
return Request.blank('')
@pytest.fixture
def mock_request():
return create_mock_request()
def create_mock_response():
return Response()
@pytest.fixture
def mock_response():
return create_mock_response()