1. self contained
The test case can be run either in isolation or in arbitrary combination with any number of other test cases.

2. In unittest of Python, If setUp() succeeded, the tearDown() method will be run whether runTest() succeeded or not.

3. In unittest of Python, there are some ways to create test suite.

--------------------
suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
--------------------
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('testDefaultSize'))
suite.addTest(WidgetTestCase('testResize'))
return suite
--------------------
def suite():
tests = ['testDefaultSize', 'testResize']
return unittest.TestSuite(map(WidgetTestCase, tests))
4. To use old test without converting every old test function to a TestCase subclass, unittest provides a FunctionTestCase class. This subclass of TestCase can be used to wrap an existing test function. Set-up and tear-down functions can also be provided.
def testSomething():
something = makeSomething()
assert something.name is not None
# ...

testcase = unittest.FunctionTestCase(testSomething)
or
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
5. TestCase.setUp()
This is called immediately before calling the test method; any exception raised by this method will be considered an error rather than a test failure. The default implementation does nothing.

6. The methods of TestCase used by the test implementation to check conditions and report failures can be get here.

7. ad-hoc means that there are no installation requirements whatsoever on the remote side. (from here)

8. By default, py.test catches text written to stdout/stderr during the execution of each individual test. This output will only be displayed however if the test fails, each failing test that produced output during the running of the test will have its output displayed in the recorded stdout section.

9. Disabling a test class
If you want to disable a complete test class you can set the class-level attribute disabled. For example, in order to avoid running some tests on Win32:
class TestPosixOnly:
disabled = sys.platform == 'win32'
def test_xxx(self):
...

It is wonderful for me to know that my application was accepted by Google Summer of Code program (GSoC). This summer I will work for improving py.test compatibility with several versions of Python, especially 3k. Besides, better-formatted output of regression tests and code coverage will be shown regularly on Snakebite. This project, accepted into Python Software Foundation (PSF), was inspired by Titus Brown, and will be mentored by Holger Krekel. Titus and Holger have given me many precious advices and suggestions, which are greatly appreciated.

There is no need to keep my proposal from public view, for it is against the spirit of open source. Thus, I paste it as following, and all comments, advices, or suggestions are welcome.

----GSoC Application Proposal----

ABOUT ME
My name is Yang Yang, a Ph.D. student in Computer Science at Michigan State University. As a teaching assistant of a Python course for nearly two years, I found that Python is such an amazing programming language that freshman can learn programming concepts effectively without being trapped in lower level details, meanwhile it is very powerful and can be used in almost everywhere. I am using Python almost every day, ranging from my research work to courses projects. Compared with C++, Python could save me lots of time in programming, thanks to its fewer alternatives and elegant coding style.

I still remember the time when we were developing a P2P-VoD application using C++. We have to write our own trace function and every one took charge of testing his/her own modules. Lacking of testing experience, we had to spend excessive time on debugging. Thus, knowing that py.test is aiming to provide a powerful testing framework, I am eager to improve this tool to make it usable for Core Python3k developers. So, developers can run tests without thought and more concentrate on their own modules.

This project will be my main work in this summer, and I am able to be in contact with mentors and community. Furthermore, finishing this project does not mean I already reach the destination. I will still keep in contact within PSF community and keep making my contribution.

CONTACT INFO
email: yangyan5 AT msu DOT edu
yangyan5 AT gmail DOT com
cell: 517-614-6078
IRC nick: yangyang

TITLE
Improve Unit Testing Framework for Core Python3k

ABSTRACT
In this project, I will make py.test compatible to Core Python3k test files and introduce some features to py.test, such that Python developers can run unit testing easier. Besides, regression test suite will be run over multiple platforms regularly on Snakebite, integrated with build-bot or other facilities.

SUMMARY
Unit testing is very important in software development and Python has already provided a unit testing framework unittest. Although unittest supports some features such as test automation and collection, tests still cannot be run without thought, which means that we still need to register the tests we want to run. Thus, some unit testing framework arises, such as py.test and nose. py.test is already used in PyPy and it has many excellent features, such as automatically collecting and executing tests, selecting/unselecting tests by keyword, and distributing tests to multiple CPUs or machines. Similarly, nose provides a number of excellent features as well. For example, nose has the ability to run tests based on specific tags, i.e. tests can be run selectively without manually generating test suite. Besides, nose can transparently wrap tests with code coverage recording. However, the prerequisite of using these features of py.test and nose is that the tests must be discoverable and executable, which cannot be guaranteed in Core Python. Besides, py.test is still not compatible with Python3k. Thus, I plan to introduce several features that make py.test and nose compatible and convenient to run the hundreds of test files in Core Python.

My effort will mainly focus on Python3k and be seven-fold. The first feature I'd like to contribute is to make py.test compatible with Python3k as well as Python2.4, which will be the basis of my later work. Second, I will provide a py.test plug-in for Python3k, Python2.6, and Python2.5 that could "understand" the conditions under which regrtest.py, the current test runner, finds and runs tests. Third, as Jython is becoming more and more popular, I plan to port the plug-in to make py.test could be used in Jython. Fourth, I will set up regular test runs for Core Python3k on Snakebite such that regression test suite across multiple platforms can be recorded and posted. And, for daily run reporting on Snakebite, I will work on integrating with build-bot or other facilities. Fifth, to help developers test their code over different version of Python, I will check the latest features of unittest.py and doctest.py of Python3k and make them compatible with previous versions of Python. Sixth, aiming to increase the test coverage in Python3k, I plan to write some test cases and report current test coverage for python modules in stdlib and list achieved improvements. Although py.test has pytest_figleaf which offers coverage report, the report is raw and needs configuration to make it useful and meaningful for developers. Last but not least, to collaborate with nose, a plug-in for py.test will be provided to invoke and run nose-style tests, which means to make py.test could discover and execute nose-style tests.

Through all of my work, py.test will be made compatible with multiple versions of CPython and Jython when running regression test suite, without modifying tests too much. In addition, the regression tests and code coverage result over multiple platforms will be shown on Snakebite.

SCHEDULE
April 20 - May 22: Get to know mentors and community. Dive into the details of py.test, regrtest.py, and nose.
May 23 - June 7: Port py.test to Python3k, keeping compatible with Python2.4 as well.. (including debugging)
June 8 - June 21: Write a Plug-in to make py.test compatible with regrtest of Python3k, Python2.6, and Python2.5. (including debugging)
June 22 - June 28: Port py.test and plug-in to Jython. (including debugging)
June 29 - July 5: Port latest features of Python3k to previous versions. (including debugging)
July 6 - July 15: Set up regular regression test runs on Snakebite. (keeping in touch with python-dev)
July 16 - July 26: Write test cases, report current test coverage and list achieved improvements. (keeping in touch with python-dev)
July 27 - August 2: Write a plug-in for py.test to invoke/run nose-style tests.
August 3 - August 10: Documentation

DELIVERABLES
1. Port py.test to Python3k, keeping compatible with Python2.4 as well.
2. A plug-in to make py.test compatible with regrtest of Python3k, Python2.6, and Python2.5.
3. Port py.test and plug-in to Jython.
4. Port latest features of Python3k to previous versions.
5. Regression test suite regular report on Snakebite, integrated with build-bot or other facilities.
6. Report current test coverage and list achieved improvements. The report will be developer-friendly.
7. A plug-in for py.test to invoke/run nose-style tests.

BENEFITS TO COMMUNITY
1. Make unit testing on Core Python3k and other Python versions easier by allowing developers to use py.test with some convenient features.
2. Give developers a clear view on regression test and code coverage result over multiple platforms.
-------End of Proposal--------

The exciting and busy summer is coming!

Mercurial is a distributed source version control system. Compared with subversion, Mercurial is much more scalable, and everyone can commit his/her own effort. It is becoming more and more popular, and Python has switched to Mercurial recently. Here is a tutorial written by Bryan O'Sullivan and all notes below are extracted from it.

1. log
$ hg log -r [-v] [-p]
-v: verbose mode
-p: show content of a change

2. status
$ hg status
Show what Mercurial knows about the files in repository.

3. incoming, pull, update
We use pull to get the changesets from "remote" repository. But, to avoid blindly fetching, we should use incoming first to give us a clear view of what will be transferred.
$ hg incoming remote_repository
$ hg pull remote_repository
Because pull only bring changes into repository, we should use update to get a working copy. So, we should run:
$ hg update

4. outgoing, push, update
outgoing command will tell us what changes would be pushed into another repository. push command does the actual push. Then use update to get a working copy.
$ hg outgoing remote_repository
$ hg push remote_repository
$ hg update

5. heads, parents
We can view the heads in a repository using the heads command.
$ hg heads
Note: heads is different with parents. parents command is used to find out what revision the working directory is at.
$ hg parents

6. Removing a file does not affect its history. It has only two effects:

  • It removes the current version of the file from the working directory.
  • It stops Mercurial from tracking changes to the file, from the time of the next commit.

7. Mercurial considers a file that you have deleted, but not used hg remove to delete, to be missing. If you deleted the missing file by accident, give hg revert the name of the file to recover. It will reappear, in unmodified form.

8. Mercurial offers a combination command, hg addremove, that adds untracked files and marks missing files as removed.

Holger Krekel shared with me an interesting post which talks about some typical prototypes of programmers. It is so true that I found those characteristics in myself and teammates very often. For example, I thought it embarrassing me to let others see my iterative work before I reach a milestone. And the result is that I have no time to refactor my code and have to continue my work based on the fragile and awkward "code bomb". Thanks to that post, I am trying to put the advices into practice.

Recently I have been shifting from Python2.x to Python3.x. So, all notes below are only guaranteed in Python3.x.

1. all(iterable) and any(iterable)
They are equivalent to following functions respectively:

def all(iterable):
for element in iterable:
if not element:
return False
return True
def any(iterable):
for element in iterable:
if element:
return True
return False
2. bin(number) and hex(number)
Convert an integer number to a binary or hexadecimal string (starts with '0b' or '0x'). The result is a valid Python expression.

3. chr(i)
Return the string of one character whose Unicode codepoint is the integer i. For example, chr(97) returns the string 'a'. This is the inverse of ord().

4. classmethod
The @classmethod form is a function decorator. A class method receives the class as implicit first argument, just like an instance method receives the instance. To declare a class method, use this idiom:

class C:
@classmethod
def f(cls, arg1, arg2, ...): ...
It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class. If a class method is called for a derived class, the derived class object is passed as the implied first argument. Note that class methods are different than C++ or Java static methods.

5. delattr(object, name)
This is a relative of setattr(). The arguments are an object and a string. The string must be the name of one of the object’s attributes. The function deletes the named attribute, provided the object allows it.

6. dir([object])
Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.

7. divmod(a, b)
Take two (non complex) numbers as arguments and return a pair of numbers consisting of their quotient and remainder.

8. enumerate(iterable[, start=0])
Return a tuple containing a count (from start which defaults to 0) and the corresponding value obtained from iterating over iterable.

9. eval(expression[, globals[, locals]]), exec(object[, globals[, locals]]), and compile(source, filename, mode[, flags[, dont_inherit]])
Here I just show some simple examples. For more details, please check here.

>>> glo = {'x':5, 'y':6}
>>> eval('x+y', glo)
11
>>> glo = {'aList':[1,2,3]}
>>> exec('for i in aList: print i', glo)
1
2
3
>>> aString = 'for i in range(3): print i'
>>> aStatement = compile(aString, '', 'exec')
>>> exec(aStatement)
0
1
2
Note:
a) The built-in functions globals() and locals() return the current global and local dictionary, respectively, which may be useful to pass around for use as the second and third argument to exec().
b) execfile function is no longer used in Python3.x. Instead of execfile(fn) use exec(open(fn).read()).

10. frozenset([iterable])
To represent sets of sets, the inner sets must be frozenset objects.

11. getattr(object, name[, default])
Return the value of the named attributed of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar.

12. hasattr(object, name)
The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.)

13. hash(object)
Return the hash value of the object (if it has one). Hash values are integers. They are used to quickly compare dictionary keys during a dictionary lookup. Numeric values that compare equal have the same hash value (even if they are of different types, as is the case for 1 and 1.0).

14. id(object)
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id value. (Implementation note: this is the address of the object.)

15. memoryview(obj)
Return a “memory view” object created from the given argument. For example:
>>> data = bytearray(b'abcefg')
>>> v = memoryview(data)
>>> v.readonly
False
>>> v[0] = 'z'
>>> data
bytearray(b'zbcefg')
>>> v[1:4] = b'123'
>>> data
bytearray(b'a123fg')
>>> v[2] = b'spam'
Traceback (most recent call last):
File "", line 1, in
ValueError: cannot modify size of memoryview object
There is a tolist() method which returns the data in the buffer as a list of integers:
>>> memoryview(b'abc').tolist()
[97, 98, 99]
16. setattr(object, name, value)
This is the counterpart of getattr(). The arguments are an object, a string and an arbitrary value. The string may name an existing attribute or a new attribute. The function assigns the value to the attribute, provided the object allows it.

17. staticmethod
A static method does not receive an implicit first argument. To declare a static method, use this idiom:
class C:
@staticmethod
def f(arg1, arg2, ...): ...
It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class.

18. vars([object])
Without arguments, return a dictionary corresponding to the current local symbol table. With a module, class or class instance object as argument (or anything else that has a __dict__ attribute), returns a dictionary corresponding to the object’s symbol table.