Exploring Python nosetests and unittests for a simple Markov transition function

Objectives

  • Understand how unit tests work.
  • Investigate unittest and nose, a popular unit test framework.
  • Understand the failure modes of my choice function.
  • Write some unit tests for my choice function.

In [13]:
# imports for notebook
import numpy as np

Unit tests with method based code


In [220]:
%%file choice.py
# -*- coding: ascii -*-
""" Exploring unit tests.
    Simple code to implement a simple Markov transition function.
    
"""
__author__ = "Mike McFarlane (mike@mikemcfarlane.co.uk)"
__version__ = "$Revision: 0 $"
__date__ = "$Date: 11-04-14"
__copyright__ =  "Copyright (c) Mike McFarlane 2014"
__license__ = "TBC"

import random
import numpy as np
import custom_exceptions as ce

def choice2(inArray):
    """ Simple function to implement a Markov transition function.

    """
    randNum = np.random.random()
    cum = 0
    sumVal = np.sum(inArray)
    if not abs(sumVal - 1.0) < 1e-10:
        #print "not a P array"
        raise ce.MatrixError("Not a valid array")
    else:
        for count, i in enumerate(inArray):
            cum += i
            if cum >= randNum:
                return count
            
if __name__ == '__main__':
    print choice2([1])


Overwriting choice.py

In [221]:
%%file custom_exceptions.py
# -*- coding: ascii -*-
""" Exploring unit tests.
    Custom exceptions classes for choice.py. 

"""
__author__ = "Mike McFarlane (mike@mikemcfarlane.co.uk)"
__version__ = "$Revision: 0 $"
__date__ = "$Date: 11-04-14"
__copyright__ =  "Copyright (c) Mike McFarlane 2014"
__license__ = "TBC"


class MatrixError(Exception):
    """ Raised when wrong matrix error. 
    
    """
    pass


Overwriting custom_exceptions.py

In [222]:
%%file choicetest_nosetests.py
# -*- coding: ascii -*-
""" Exploring unit tests.
    Tests for nose for choice.py.
    
"""
__author__ = "Mike McFarlane (mike@mikemcfarlane.co.uk)"
__version__ = "$Revision: 0 $"
__date__ = "$Date: 11-04-14"
__copyright__ =  "Copyright (c) Mike McFarlane 2014"
__license__ = "TBC"

import choice

def test_range():
    assert choice.choice2([1]) >= 0
    
def test_bad_range():
    assert choice.choice2([2]) >= 0
    
def test_large_range():
    assert choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.01]) >= 0
    
def test_large_bad_range():
    assert choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.1]) >= 0


Overwriting choicetest_nosetests.py

In [76]:
%%file choicetest_unittest.py
# -*- coding: ascii -*-
""" Exploring unit tests.
    Unit tests for unittest for choice.py. 

"""
__author__ = "Mike McFarlane (mike@mikemcfarlane.co.uk)"
__version__ = "$Revision: 0 $"
__date__ = "$Date: 11-04-14"
__copyright__ =  "Copyright (c) Mike McFarlane 2014"
__license__ = "TBC"

import choice
import unittest
import numpy as np

class RangeTests(unittest.TestCase):
    def test_range(self):
        a = choice.choice2([1])
        b = 0
        self.assertGreaterEqual(a, b)
        
    def test_bad_range(self):
        a = choice.choice2([2])
        b = 0
        self.assertGreaterEqual(a, b)
        
    def test_large_range(self):
        a = choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.01])
        b = 0
        self.assertGreaterEqual(a, b)
    
    def test_large_bad_range(self):      
        a = choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.1])
        b = 0
        self.assertGreaterEqual(a, b)
        
    def test_huge_matrix(self):
        arraySize = 1000
        array = np.random.random(arraySize)
        arraySum = np.sum(array)
        arrayNormalised = array / arraySum
        testValue = choice.choice2(arrayNormalised)
        result = 0
        self.assertGreaterEqual(testValue, result)
        
    def test_multirow_matrix(self):
        a = choice.choice2([[0.5, 0.5], [0.5, 0.5]])
        b = 0
        self.assertGreaterEqual(a, b)
    

if __name__ == "__main__":
    unittest.main()


Overwriting choicetest_unittest.py

In [74]:
!ls -la


total 248
drwxr-xr-x@ 14 mikemcfarlane  staff    476 13 Mar 23:03 .
drwxr-xr-x   7 mikemcfarlane  staff    238 12 Mar 15:10 ..
drwxr-xr-x   3 mikemcfarlane  staff    102 11 Mar 14:12 .ipynb_checkpoints
-rw-r--r--   1 mikemcfarlane  staff   1628 13 Mar 22:41 Markov_tickles.py
-rw-r--r--   1 mikemcfarlane  staff   2774 13 Mar 23:03 Markov_tickles.pyc
-rw-r--r--   1 mikemcfarlane  staff   1609 13 Mar 23:02 Markov_tickles_unittest.py
-rw-r--r--   1 mikemcfarlane  staff  82757 14 Mar 17:23 Unit_test_examples.ipynb
-rw-r--r--@  1 mikemcfarlane  staff    846 11 Mar 16:42 choice.py
-rw-r--r--   1 mikemcfarlane  staff   1117 11 Mar 16:43 choice.pyc
-rw-r--r--   1 mikemcfarlane  staff    614 11 Mar 16:43 choicetest_nosetests.py
-rw-r--r--   1 mikemcfarlane  staff   1808 11 Mar 16:43 choicetest_nosetests.pyc
-rw-r--r--   1 mikemcfarlane  staff   1414 14 Mar 17:24 choicetest_unittest.py
-rw-r--r--   1 mikemcfarlane  staff    362 11 Mar 16:42 custom_exceptions.py
-rw-r--r--   1 mikemcfarlane  staff    889 11 Mar 16:43 custom_exceptions.pyc

In [225]:
import sys
if 'choice' in sys.modules: 
    print "Module present, will delete and import."
    del(sys.modules['choice'])
import choice

print choice.__version__

print "1: ", choice.choice2([1])
print "2: ", choice.choice2([2])
print "3: ", choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.01])
print "4: ", choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.1])


---------------------------------------------------------------------------
MatrixError                               Traceback (most recent call last)
<ipython-input-225-c786bd10754d> in <module>()
      8 
      9 print "1: ", choice.choice2([1])
---> 10 print "2: ", choice.choice2([2])
     11 print "3: ", choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.01])
     12 print "4: ", choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.1])

/Users/mikemcfarlane/Dropbox/Code/Repositories/NAO/TickleMeNAO/Idea_Development/nose_test_example/choice.py in choice2(inArray)
     23     if not abs(sumVal - 1.0) < 1e-10:
     24         #print "not a P array"
---> 25         raise ce.MatrixError("Not a valid array")
     26     else:
     27         for count, i in enumerate(inArray):

MatrixError: Not a valid array
Module present, will delete and import.
$Revision: 0 $
1:  0
2: 

In [227]:
!~/Library/Enthought/Canopy_64bit/User/bin/python choice.py


0

In [228]:
!~/Library/Enthought/Canopy_64bit/User/bin/nosetests -v choicetest_nosetests.py


choicetest_nosetests.test_range ... ok
choicetest_nosetests.test_bad_range ... ERROR
choicetest_nosetests.test_large_range ... ok
choicetest_nosetests.test_large_bad_range ... ERROR

======================================================================
ERROR: choicetest_nosetests.test_bad_range
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/mikemcfarlane/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/NAO/TickleMeNAO/Idea_Development/nose_test_example/choicetest_nosetests.py", line 18, in test_bad_range
    assert choice.choice2([2]) >= 0
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/NAO/TickleMeNAO/Idea_Development/nose_test_example/choice.py", line 25, in choice2
    raise ce.MatrixError("Not a valid array")
MatrixError: Not a valid array

======================================================================
ERROR: choicetest_nosetests.test_large_bad_range
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/mikemcfarlane/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/NAO/TickleMeNAO/Idea_Development/nose_test_example/choicetest_nosetests.py", line 24, in test_large_bad_range
    assert choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.1]) >= 0
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/NAO/TickleMeNAO/Idea_Development/nose_test_example/choice.py", line 25, in choice2
    raise ce.MatrixError("Not a valid array")
MatrixError: Not a valid array

----------------------------------------------------------------------
Ran 4 tests in 0.002s

FAILED (errors=2)

In [77]:
!~/Library/Enthought/Canopy_64bit/User/bin/python choicetest_unittest.py


E.E.E.
======================================================================
ERROR: test_bad_range (__main__.RangeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "choicetest_unittest.py", line 23, in test_bad_range
    a = choice.choice2([2])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/choice.py", line 25, in choice2
    raise ce.MatrixError("Not a valid array")
MatrixError: Not a valid array

======================================================================
ERROR: test_large_bad_range (__main__.RangeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "choicetest_unittest.py", line 33, in test_large_bad_range
    a = choice.choice2([0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.09, 0.1])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/choice.py", line 25, in choice2
    raise ce.MatrixError("Not a valid array")
MatrixError: Not a valid array

======================================================================
ERROR: test_multirow_matrix (__main__.RangeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "choicetest_unittest.py", line 47, in test_multirow_matrix
    a = choice.choice2([[0.5, 0.5], [0.5, 0.5]])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/choice.py", line 25, in choice2
    raise ce.MatrixError("Not a valid array")
MatrixError: Not a valid array

----------------------------------------------------------------------
Ran 6 tests in 0.001s

FAILED (errors=3)

Unit tests with classes in NAO robot code

  1. Running tests without init and not inheriting ALModule. If inherits ALModule get error "Could not create a module, as there is no current broker in Python's world".
  2. Test methods must start method name with 'test' to run

In [1]:
%%file Markov_tickles.py
# -*- coding: ascii -*-
""" NAO responds to being tickled.


"""

import time
import sys
import numpy as np


from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

NAO_IP = "mistcalf.local"

# Global variables to store module instances and proxies
MarkovTickle = None

class MarkovTickleModule():
	""" Simple module for tickling NAO. 

	"""

	# def __init__(self, name):
	# 	""" Initialise module. 

	# 	"""
	# 	ALModule.__init__(self, name)
		

	def markovChoice(self, inMatrix):
		""" Chooses a value from a Markov transition matrix.

		"""
		randNum = np.random.random()
		cum = 0
		
		if round(np.sum(inMatrix)) != 1:
			# print "This is not a p array."
			raise ValueError
		else:
			for index, probability in enumerate(inMatrix):
				cum += probability
				if cum > randNum:
					return index
		
	def mainTask(self):
		""" Temp main task.

		"""
		# Run forever
		while True:
			print ("Alive!")
			print "I choose: ", self.markovChoice([0.25, 0.25, 0.25, 0.25])
			time.sleep(1.0)


def main():
	""" Main entry point

	"""
	myBroker = ALBroker("myBroker", "0.0.0.0", 0, NAO_IP, 9559)

	global MarkovTickle
	MarkovTickle = MarkovTickleModule("MarkovTickle")

	print "Running, hit CTRL+C to stop script"
	MarkovTickle.mainTask()

	try:
		while True:
			time.sleep(1)
	except KeyboardInterrupt:
		print "Interrupted by user, shutting down"
		# stop any post tasks
		# eg void ALModule::stop(const int& id)
		try:
			myBroker.shutdown()
		except Exception, e:
			print "Error shutting down broker: ", e
		try:
			sys.exit(0)
		except Exception, e:
			print "Error exiting system: ", e


if __name__ == "__main__":
	main()


Writing Markov_tickles.py

In [2]:
%%file Markov_tickles_unittest.py
# -*- coding: ascii -*-
""" Unit tests using unittest framework for Markov_tickles.py.

"""


#from Markov_tickles import MarkovTickleModule as mt
from Markov_tickles import MarkovTickleModule
import unittest


class ToMarkovChoiceGoodInput(unittest.TestCase):
	""" Markov choice should give known result with known input.

	"""

	def setUp(self):
		self.mt = MarkovTickleModule()	
	
	def testSmallMatrix(self):
		a = self.mt.markovChoice([1])
		b = 0
		self.assertGreaterEqual(a, b)

	def testLargeMatrix(self):
		a = self.mt.markovChoice([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
		b = 0
		self.assertGreaterEqual(a, b)


class ToMarkovChoiceBadInput(unittest.TestCase):
	""" Markov choice should give error if bad input.

	"""

	def setUp(self):
		self.mt = MarkovTickleModule()
	
	def testSmallMatrix(self):
		a = self.mt.markovChoice([2])
		b = 0
		self.assertGreaterEqual(a, b)

	def testLargeMatrix(self):
		a = self.mt.markovChoice([0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
		b = 0
		self.assertGreaterEqual(a, b)


if __name__ == "__main__":
	unittest.main()


Writing Markov_tickles_unittest.py

In [3]:
!python Markov_tickles_unittest.py


EE..
======================================================================
ERROR: testLargeMatrix (__main__.ToMarkovChoiceBadInput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Markov_tickles_unittest.py", line 45, in testLargeMatrix
    a = self.mt.markovChoice([0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/Markov_tickles.py", line 42, in markovChoice
    raise ValueError
ValueError

======================================================================
ERROR: testSmallMatrix (__main__.ToMarkovChoiceBadInput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Markov_tickles_unittest.py", line 40, in testSmallMatrix
    a = self.mt.markovChoice([2])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/Markov_tickles.py", line 42, in markovChoice
    raise ValueError
ValueError

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (errors=2)
  1. Running tests with init and inheriting ALModule. Using standard NAO instance as global variable technique.

In [7]:
%%file Markov_tickles.py
# -*- coding: ascii -*-
""" NAO responds to being tickled.


"""

import time
import sys
import numpy as np


from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

NAO_IP = "mistcalf.local"

# Global variables to store module instances and proxies
MarkovTickle = None

class MarkovTickleModule(ALModule):
	""" Simple module for tickling NAO. 

	"""

	def __init__(self, name):
		""" Initialise module. 

		"""
		ALModule.__init__(self, name)
		

	def markovChoice(self, inMatrix):
		""" Chooses a value from a Markov transition matrix.

		"""
		randNum = np.random.random()
		cum = 0
		
		if round(np.sum(inMatrix)) != 1:
			# print "This is not a p array."
			raise ValueError
		else:
			for index, probability in enumerate(inMatrix):
				cum += probability
				if cum > randNum:
					return index
		
	def mainTask(self):
		""" Temp main task.

		"""
		# Run forever
		while True:
			print ("Alive!")
			print "I choose: ", self.markovChoice([0.25, 0.25, 0.25, 0.25])
			time.sleep(1.0)


def main():
	""" Main entry point

	"""
	myBroker = ALBroker("myBroker", "0.0.0.0", 0, NAO_IP, 9559)

	global MarkovTickle
	MarkovTickle = MarkovTickleModule("MarkovTickle")

	print "Running, hit CTRL+C to stop script"
	MarkovTickle.mainTask()

	try:
		while True:
			time.sleep(1)
	except KeyboardInterrupt:
		print "Interrupted by user, shutting down"
		# stop any post tasks
		# eg void ALModule::stop(const int& id)
		try:
			myBroker.shutdown()
		except Exception, e:
			print "Error shutting down broker: ", e
		try:
			sys.exit(0)
		except Exception, e:
			print "Error exiting system: ", e


if __name__ == "__main__":
	main()


Overwriting Markov_tickles.py

In [8]:
%%file Markov_tickles_unittest.py
# -*- coding: ascii -*-
""" Unit tests using unittest framework for Markov_tickles.py.

"""


#from Markov_tickles import MarkovTickleModule as mt
from Markov_tickles import MarkovTickleModule
import unittest

from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

NAO_IP = "mistcalf.local"

# Global variables to store module instances and proxies
MarkovTickle = None

class ToMarkovChoiceGoodInput(unittest.TestCase):
	""" Markov choice should give known result with known input.

	"""

	# def setUp(self):
	# 	self.mt = MarkovTickleModule("test")

	global MarkovTickle	
	
	def testSmallMatrix(self):
		a = MarkovTickle.markovChoice([1])
		b = 0
		self.assertGreaterEqual(a, b)

	def testLargeMatrix(self):
		a = MarkovTickle.markovChoice([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
		b = 0
		self.assertGreaterEqual(a, b)


class ToMarkovChoiceBadInput(unittest.TestCase):
	""" Markov choice should give error if bad input.

	"""

	# def setUp(self):
	# 	self.mt = MarkovTickleModule("test")

	global MarkovTickle
	
	def testSmallMatrix(self):
		a = MarkovTickle.markovChoice([2])
		b = 0
		self.assertGreaterEqual(a, b)

	def testLargeMatrix(self):
		a = MarkovTickle.markovChoice([0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
		b = 0
		self.assertGreaterEqual(a, b)


if __name__ == "__main__":
	myBroker = ALBroker("myBroker", "0.0.0.0", 0, NAO_IP, 9559)

	global MarkovTickle
	MarkovTickle = MarkovTickleModule("MarkovTickle")

	unittest.main()

	myBroker.shutdown()


Overwriting Markov_tickles_unittest.py

In [9]:
!python Markov_tickles_unittest.py


Markov_tickles_unittest.py:65: SyntaxWarning: name 'MarkovTickle' is assigned to before global declaration
  global MarkovTickle
inaoqi-broker: construct at 0.0.0.0:0, parent : mistcalf.local:9559
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.0.1.152:49810
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:49810
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.6:49810
[W] 4359 qitype.metaobject: Method(112) already defined (and overriden): BIND_PYTHON::(m)
[W] 4359 qitype.metaobject: Method(113) already defined (and overriden): addParam::(m)
[W] 4359 qitype.metaobject: Method(114) already defined (and overriden): autoBind::(m)
[W] 4359 qitype.metaobject: Method(100) already defined (and overriden): exit::()
[W] 4359 qitype.metaobject: Method(115) already defined (and overriden): functionName::(m)
[W] 4359 qitype.metaobject: Method(110) already defined (and overriden): getBrokerName::()
[W] 4359 qitype.metaobject: Method(116) already defined (and overriden): getModule::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(123) already defined (and overriden): setModuleDescription::(m)
[W] 4359 qitype.metaobject: Method(102) already defined (and overriden): version::()
EE..
======================================================================
ERROR: testLargeMatrix (__main__.ToMarkovChoiceBadInput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Markov_tickles_unittest.py", line 57, in testLargeMatrix
    a = MarkovTickle.markovChoice([0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/Markov_tickles.py", line 42, in markovChoice
    raise ValueError
ValueError

======================================================================
ERROR: testSmallMatrix (__main__.ToMarkovChoiceBadInput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Markov_tickles_unittest.py", line 52, in testSmallMatrix
    a = MarkovTickle.markovChoice([2])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/Markov_tickles.py", line 42, in markovChoice
    raise ValueError
ValueError

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (errors=2)
  1. Running tests with init and inheriting ALModule. Creating instance and setting up broker in setUp(), then destroying instance and stopping broker in tearDown().
  2. This is significantly slower but possible better practise in more complex tests to prevent variable value problems.

In [10]:
%%file Markov_tickles.py
# -*- coding: ascii -*-
""" NAO responds to being tickled.


"""

import time
import sys
import numpy as np


from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

NAO_IP = "mistcalf.local"

# Global variables to store module instances and proxies
MarkovTickle = None

class MarkovTickleModule(ALModule):
	""" Simple module for tickling NAO. 

	"""

	def __init__(self, name):
		""" Initialise module. 

		"""
		ALModule.__init__(self, name)
		

	def markovChoice(self, inMatrix):
		""" Chooses a value from a Markov transition matrix.

		"""
		randNum = np.random.random()
		cum = 0
		
		if round(np.sum(inMatrix)) != 1:
			# print "This is not a p array."
			raise ValueError
		else:
			for index, probability in enumerate(inMatrix):
				cum += probability
				if cum > randNum:
					return index
		
	def mainTask(self):
		""" Temp main task.

		"""
		# Run forever
		while True:
			print ("Alive!")
			print "I choose: ", self.markovChoice([0.25, 0.25, 0.25, 0.25])
			time.sleep(1.0)


def main():
	""" Main entry point

	"""
	myBroker = ALBroker("myBroker", "0.0.0.0", 0, NAO_IP, 9559)

	global MarkovTickle
	MarkovTickle = MarkovTickleModule("MarkovTickle")

	print "Running, hit CTRL+C to stop script"
	MarkovTickle.mainTask()

	try:
		while True:
			time.sleep(1)
	except KeyboardInterrupt:
		print "Interrupted by user, shutting down"
		# stop any post tasks
		# eg void ALModule::stop(const int& id)
		try:
			myBroker.shutdown()
		except Exception, e:
			print "Error shutting down broker: ", e
		try:
			sys.exit(0)
		except Exception, e:
			print "Error exiting system: ", e


if __name__ == "__main__":
	main()


Overwriting Markov_tickles.py

In [11]:
%%file Markov_tickles_unittest.py
# -*- coding: ascii -*-
""" Unit tests using unittest framework for Markov_tickles.py.

"""


#from Markov_tickles import MarkovTickleModule as mt
from Markov_tickles import MarkovTickleModule
import unittest

from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

NAO_IP = "mistcalf.local"

class ToMarkovChoiceGoodInput(unittest.TestCase):
	""" Markov choice should give known result with known input.

	"""

	def setUp(self):
		self.myBroker = ALBroker("myBroker", "0.0.0.0", 0, NAO_IP, 9559)
		self.MarkovTickle = MarkovTickleModule("MarkovTickle")

	def tearDown(self):
		# self.MarkovTickle.dispose()
		self.MarkovTickle = None
		self.myBroker.shutdown()
		
	def testSmallMatrix(self):
		a = self.MarkovTickle.markovChoice([1])
		b = 0
		self.assertGreaterEqual(a, b)

	def testLargeMatrix(self):
		a = self.MarkovTickle.markovChoice([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
		b = 0
		self.assertGreaterEqual(a, b)


class ToMarkovChoiceBadInput(unittest.TestCase):
	""" Markov choice should give error if bad input.

	"""

	def setUp(self):
		self.myBroker = ALBroker("myBroker", "0.0.0.0", 0, NAO_IP, 9559)
		self.MarkovTickle = MarkovTickleModule("MarkovTickle")

	def tearDown(self):
		# self.MarkovTickle.dispose()
		self.MarkovTickle = None
		self.myBroker.shutdown()
	
	def testSmallMatrix(self):
		a = self.MarkovTickle.markovChoice([2])
		b = 0
		self.assertGreaterEqual(a, b)

	def testLargeMatrix(self):
		a = self.MarkovTickle.markovChoice([0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
		b = 0
		self.assertGreaterEqual(a, b)


if __name__ == "__main__":
	unittest.main()


Overwriting Markov_tickles_unittest.py

In [12]:
!python Markov_tickles_unittest.py


inaoqi-broker: construct at 0.0.0.0:0, parent : mistcalf.local:9559
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.0.1.152:50037
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:50037
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.6:50037
[W] 4359 qitype.metaobject: Method(112) already defined (and overriden): BIND_PYTHON::(m)
[W] 4359 qitype.metaobject: Method(113) already defined (and overriden): addParam::(m)
[W] 4359 qitype.metaobject: Method(114) already defined (and overriden): autoBind::(m)
[W] 4359 qitype.metaobject: Method(100) already defined (and overriden): exit::()
[W] 4359 qitype.metaobject: Method(115) already defined (and overriden): functionName::(m)
[W] 4359 qitype.metaobject: Method(110) already defined (and overriden): getBrokerName::()
[W] 4359 qitype.metaobject: Method(116) already defined (and overriden): getModule::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(123) already defined (and overriden): setModuleDescription::(m)
[W] 4359 qitype.metaobject: Method(102) already defined (and overriden): version::()
E[I] 4359 behavior.inaoqi: Stop broker myBroker

inaoqi-broker: construct at 0.0.0.0:0, parent : mistcalf.local:9559
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.0.1.152:50039
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:50039
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.6:50039
[W] 4359 qitype.metaobject: Method(112) already defined (and overriden): BIND_PYTHON::(m)
[W] 4359 qitype.metaobject: Method(113) already defined (and overriden): addParam::(m)
[W] 4359 qitype.metaobject: Method(114) already defined (and overriden): autoBind::(m)
[W] 4359 qitype.metaobject: Method(100) already defined (and overriden): exit::()
[W] 4359 qitype.metaobject: Method(115) already defined (and overriden): functionName::(m)
[W] 4359 qitype.metaobject: Method(110) already defined (and overriden): getBrokerName::()
[W] 4359 qitype.metaobject: Method(116) already defined (and overriden): getModule::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(123) already defined (and overriden): setModuleDescription::(m)
[W] 4359 qitype.metaobject: Method(102) already defined (and overriden): version::()
E[I] 4359 behavior.inaoqi: Stop broker myBroker

inaoqi-broker: construct at 0.0.0.0:0, parent : mistcalf.local:9559
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.0.1.152:50042
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:50042
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.6:50042
[W] 4359 qitype.metaobject: Method(112) already defined (and overriden): BIND_PYTHON::(m)
[W] 4359 qitype.metaobject: Method(113) already defined (and overriden): addParam::(m)
[W] 4359 qitype.metaobject: Method(114) already defined (and overriden): autoBind::(m)
[W] 4359 qitype.metaobject: Method(100) already defined (and overriden): exit::()
[W] 4359 qitype.metaobject: Method(115) already defined (and overriden): functionName::(m)
[W] 4359 qitype.metaobject: Method(110) already defined (and overriden): getBrokerName::()
[W] 4359 qitype.metaobject: Method(116) already defined (and overriden): getModule::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(123) already defined (and overriden): setModuleDescription::(m)
[W] 4359 qitype.metaobject: Method(102) already defined (and overriden): version::()
[I] 4359 behavior.inaoqi: Stop broker myBroker

.inaoqi-broker: construct at 0.0.0.0:0, parent : mistcalf.local:9559
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.0.1.152:50044
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:50044
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.6:50044
[W] 4359 qitype.metaobject: Method(112) already defined (and overriden): BIND_PYTHON::(m)
[W] 4359 qitype.metaobject: Method(113) already defined (and overriden): addParam::(m)
[W] 4359 qitype.metaobject: Method(114) already defined (and overriden): autoBind::(m)
[W] 4359 qitype.metaobject: Method(100) already defined (and overriden): exit::()
[W] 4359 qitype.metaobject: Method(115) already defined (and overriden): functionName::(m)
[W] 4359 qitype.metaobject: Method(110) already defined (and overriden): getBrokerName::()
[W] 4359 qitype.metaobject: Method(116) already defined (and overriden): getModule::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(119) already defined (and overriden): markovChoice::(m)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(121) already defined (and overriden): pythonChanged::(mmm)
[W] 4359 qitype.metaobject: Method(123) already defined (and overriden): setModuleDescription::(m)
[W] 4359 qitype.metaobject: Method(102) already defined (and overriden): version::()
[I] 4359 behavior.inaoqi: Stop broker myBroker

.
======================================================================
ERROR: testLargeMatrix (__main__.ToMarkovChoiceBadInput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Markov_tickles_unittest.py", line 62, in testLargeMatrix
    a = self.MarkovTickle.markovChoice([0.9, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/Markov_tickles.py", line 42, in markovChoice
    raise ValueError
ValueError

======================================================================
ERROR: testSmallMatrix (__main__.ToMarkovChoiceBadInput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Markov_tickles_unittest.py", line 57, in testSmallMatrix
    a = self.MarkovTickle.markovChoice([2])
  File "/Users/mikemcfarlane/Dropbox/Code/Repositories/Code_sprints/unittest_development/Markov_tickles.py", line 42, in markovChoice
    raise ValueError
ValueError

----------------------------------------------------------------------
Ran 4 tests in 0.923s

FAILED (errors=2)

Test types for Markov transition function

  1. Good matrices of various sizes.
  2. Bad matrices of various sizes: don't sum to 1, incorrect format e.g. missing comma, more than single row.

In [65]:
# Good matrix, huge. Create a large numpy array.
array = np.arange(0., 1., 0.01)
print array


[ 0.   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9]

In [66]:
# Or with random, then normalise.
arraySize = 1000
array = np.random.random(arraySize)
print array
array_sum = np.sum(array)
array_normalised = array / array_sum
print np.sum(array_normalised)


[ 0.37098361  0.19341965  0.8691834   0.80793778  0.30489011  0.7374242
  0.42810863  0.22449066  0.18657774  0.90687905  0.85076439  0.37660514
  0.99214476  0.15796751  0.53736665  0.10936905  0.70292132  0.09372971
  0.8867162   0.96597777  0.65526065  0.18447088  0.4862304   0.04181354
  0.1824083   0.85424627  0.17475687  0.30297109  0.41528128  0.29027786
  0.25878774  0.46870082  0.89870453  0.04812565  0.28949011  0.87443966
  0.53962305  0.59713749  0.76631234  0.91413061  0.67851886  0.27741954
  0.0071842   0.82599942  0.92485758  0.82470083  0.61813385  0.7230615
  0.72736614  0.92385443  0.16068248  0.84093385  0.16646141  0.08058099
  0.006625    0.77757558  0.88541829  0.7674396   0.24172577  0.69802273
  0.97238249  0.13886628  0.22391722  0.72072277  0.57766008  0.8635132
  0.8578433   0.41087718  0.86195083  0.27099628  0.48427427  0.27314164
  0.90028     0.59276713  0.69719553  0.22390843  0.49064672  0.26513885
  0.99481753  0.25954346  0.13733677  0.63159709  0.85979     0.93602549
  0.41629246  0.28229562  0.46265628  0.37909862  0.3531573   0.37375913
  0.0965267   0.1657359   0.01515774  0.99537649  0.97371177  0.13545982
  0.59889033  0.86793833  0.98871538  0.01268097  0.57719101  0.55253496
  0.94237362  0.55210088  0.68076977  0.73846717  0.79152636  0.61254663
  0.05672334  0.24240969  0.1682584   0.27633163  0.83302027  0.01689266
  0.37196987  0.53781262  0.43701394  0.64719335  0.32384899  0.56724904
  0.9886148   0.10087056  0.24823801  0.4613438   0.5293828   0.45254499
  0.98215695  0.33735027  0.67862883  0.57969052  0.68441125  0.19334943
  0.89953561  0.53785368  0.96575176  0.77635369  0.30103153  0.8552068
  0.12728347  0.38938935  0.40113957  0.21424798  0.06882533  0.09913667
  0.48472759  0.74213842  0.94178596  0.43772781  0.98163945  0.66367786
  0.85911544  0.78146421  0.40334288  0.28727257  0.93686764  0.67688601
  0.55274959  0.04299828  0.73027468  0.08547512  0.63469081  0.72411058
  0.4666244   0.96099111  0.4902319   0.70158436  0.4550853   0.49372494
  0.74293433  0.64086651  0.39789173  0.94903279  0.4959852   0.40891465
  0.60197012  0.69479246  0.0995695   0.9673056   0.36142046  0.56323139
  0.83434011  0.51322813  0.9323776   0.99253269  0.86138181  0.83870879
  0.12162618  0.38242731  0.30543534  0.0622863   0.65216985  0.98264489
  0.6871034   0.43310837  0.93581242  0.41121863  0.77374399  0.78524188
  0.12601346  0.09838787  0.36686548  0.51266059  0.03197825  0.30615875
  0.42220926  0.47146527  0.90002809  0.4630232   0.62794898  0.54241615
  0.09328318  0.27899196  0.81793108  0.38245238  0.56482147  0.31359021
  0.05469731  0.75725549  0.86130325  0.03045971  0.74469533  0.35664237
  0.43403239  0.2217898   0.43797632  0.21183007  0.15976774  0.85947199
  0.42473635  0.02771787  0.87579294  0.92071913  0.30719109  0.87151941
  0.6900538   0.13618714  0.40126611  0.86852945  0.53761931  0.69232607
  0.91495959  0.277313    0.52782635  0.81443667  0.953199    0.60796186
  0.62692937  0.65782856  0.83579659  0.06784497  0.6497668   0.98425373
  0.74507411  0.53482364  0.79184091  0.89352398  0.58405422  0.33226319
  0.55206099  0.40822462  0.19612605  0.7373278   0.84520208  0.81222214
  0.35179475  0.50447252  0.41267578  0.92773999  0.69552246  0.05291901
  0.66190189  0.89442468  0.37498976  0.51385705  0.47408758  0.34162953
  0.781401    0.78504162  0.85373002  0.18231578  0.71972893  0.47041207
  0.62299136  0.47305174  0.7844463   0.35486984  0.94097553  0.72750693
  0.71946921  0.53894582  0.01815397  0.25212956  0.64914246  0.40239164
  0.90673573  0.89581378  0.53436447  0.21549611  0.92834233  0.4254315
  0.68855248  0.19438671  0.24258399  0.48372997  0.83727709  0.16386167
  0.68814174  0.68324968  0.17075618  0.83391517  0.58140726  0.89068048
  0.24939876  0.74135277  0.26780654  0.94542903  0.59714692  0.07070573
  0.95389772  0.37700218  0.83638953  0.90799898  0.53594563  0.64097765
  0.29893006  0.24585997  0.42485964  0.27620076  0.21913019  0.89995961
  0.53593609  0.61333281  0.17419254  0.92932802  0.89078557  0.33032082
  0.02134993  0.70152725  0.30331334  0.57643465  0.84273431  0.97600495
  0.54462977  0.95122758  0.3294137   0.12141455  0.07695139  0.18586535
  0.52495067  0.65603318  0.64905018  0.28421853  0.70096745  0.50780782
  0.47016185  0.19747853  0.5060614   0.05071627  0.63640388  0.77788524
  0.92325601  0.97892814  0.61251788  0.8998765   0.79358162  0.16043935
  0.60319311  0.42525313  0.75786353  0.17006073  0.53246546  0.94541217
  0.45775989  0.31434797  0.47925114  0.61594412  0.08163458  0.25720012
  0.94170196  0.1789038   0.64707826  0.86208608  0.07647984  0.7922903
  0.92927537  0.48362579  0.19007868  0.23838277  0.41939322  0.63444179
  0.1922735   0.78028211  0.55793919  0.77640519  0.11664181  0.14235657
  0.00924528  0.10319836  0.63244261  0.69281443  0.99252687  0.09208051
  0.81867146  0.9303387   0.83388296  0.5937541   0.83214555  0.93673697
  0.61527486  0.70119525  0.73404374  0.64956735  0.60049502  0.94933008
  0.10823242  0.30895822  0.14754926  0.41035043  0.84456715  0.65744924
  0.86774584  0.77531808  0.5644913   0.92518499  0.5383068   0.10555002
  0.34825206  0.35778177  0.07884083  0.79799379  0.03065734  0.52102365
  0.30400832  0.72257546  0.316142    0.84770688  0.46302078  0.45800235
  0.40958164  0.81829145  0.07371888  0.09786989  0.8037075   0.2833142
  0.86037369  0.6773459   0.05255857  0.04466269  0.75987826  0.22545237
  0.72653286  0.95942257  0.92594859  0.24746062  0.85401965  0.01912194
  0.93562015  0.08200391  0.60958816  0.81272677  0.54153478  0.12438595
  0.73047663  0.41330895  0.02907773  0.98601682  0.43656295  0.2884354
  0.40727453  0.86116968  0.48812364  0.40836191  0.07972633  0.19234714
  0.29744214  0.33025888  0.02191403  0.7924527   0.05290933  0.79806113
  0.33513291  0.19052821  0.77326721  0.73884967  0.03362631  0.58526349
  0.00763477  0.39895697  0.46547118  0.456166    0.51247868  0.94556692
  0.38185203  0.15069992  0.76311102  0.24875617  0.85783211  0.51075599
  0.64770188  0.38349121  0.12222119  0.55065023  0.83180081  0.15702037
  0.17709245  0.04537368  0.59562181  0.65065211  0.91701767  0.48784475
  0.24772127  0.20521992  0.91177378  0.99611883  0.9405422   0.70287215
  0.35440076  0.44728135  0.41105252  0.66513969  0.41960277  0.69735178
  0.58388384  0.89590426  0.63800904  0.77715563  0.14246006  0.68604325
  0.32836849  0.16146201  0.53475879  0.48378338  0.03638253  0.07390524
  0.55662718  0.92274897  0.42479002  0.6471838   0.7278425   0.51482971
  0.88341094  0.75957172  0.34015292  0.18910972  0.78726515  0.80219347
  0.76311637  0.54241289  0.89363129  0.72431975  0.75753247  0.62009037
  0.77837494  0.90728317  0.0547407   0.44220649  0.86451847  0.1125213
  0.13404454  0.83729628  0.34060838  0.77637922  0.09021848  0.18194812
  0.76432428  0.16873395  0.73864064  0.0904279   0.15218268  0.214818
  0.72131442  0.21408444  0.50241493  0.16639891  0.18644246  0.61119326
  0.12765106  0.54703468  0.97810912  0.81580156  0.59155879  0.79617703
  0.07033971  0.80502109  0.10082362  0.45551944  0.93345057  0.00229927
  0.3733911   0.08044771  0.85729755  0.7340866   0.7377849   0.19988129
  0.69399378  0.01861448  0.22701424  0.78197556  0.66350263  0.7928339
  0.91825167  0.56334903  0.08715081  0.13703616  0.51906981  0.93198989
  0.72275058  0.63762615  0.69337682  0.28906036  0.28615659  0.13160242
  0.54539716  0.78087009  0.09560107  0.18548952  0.83843848  0.77542172
  0.98192174  0.39994092  0.02075068  0.29725446  0.92050013  0.61685536
  0.50994003  0.30203352  0.34263866  0.12449821  0.0821521   0.82831698
  0.05499656  0.03044973  0.85734266  0.05402605  0.52905215  0.99406682
  0.54995591  0.86887684  0.8510192   0.39543692  0.77746795  0.33349553
  0.39395759  0.46870849  0.98267452  0.96362975  0.40413483  0.23571643
  0.51213575  0.91754134  0.00412216  0.64476535  0.73838896  0.68787424
  0.09533179  0.13912701  0.35889472  0.8674141   0.76908887  0.90721872
  0.42704077  0.29864489  0.36653848  0.89974881  0.80532684  0.29140009
  0.38073473  0.1886161   0.92305904  0.87619569  0.10245026  0.89120129
  0.46690408  0.93605604  0.98591962  0.00475418  0.3825049   0.39763256
  0.03812898  0.51772406  0.63868062  0.27747055  0.51057248  0.21906614
  0.07676402  0.45964682  0.42744426  0.21367795  0.92229681  0.84640462
  0.63497382  0.80721876  0.11840311  0.38964909  0.37104106  0.54189909
  0.47018142  0.70653199  0.32047203  0.29738964  0.40791227  0.84047437
  0.06150183  0.34520144  0.36139383  0.60603126  0.9787632   0.70487121
  0.05299811  0.9940748   0.85676464  0.96018931  0.00905237  0.81485865
  0.84118664  0.41777443  0.26502439  0.61454477  0.7942274   0.77612078
  0.59425198  0.94825555  0.24772522  0.74927669  0.2967743   0.59639531
  0.27790675  0.80168895  0.6537168   0.90642868  0.74202654  0.49993867
  0.95455956  0.56422885  0.86335869  0.2811451   0.48257266  0.50368962
  0.42023539  0.84939651  0.47930971  0.12843366  0.820906    0.77418321
  0.56003307  0.66130257  0.43339636  0.9570049   0.71981086  0.55661881
  0.30147783  0.45174481  0.24867598  0.67030112  0.65305363  0.02860825
  0.7619212   0.02832407  0.86648724  0.47351118  0.67177903  0.26880453
  0.64883843  0.45550169  0.59222022  0.44975641  0.65256106  0.90781332
  0.87553298  0.5284093   0.3503358   0.44737056  0.35022004  0.14436394
  0.62703034  0.99757902  0.19134522  0.99470628  0.14587419  0.89070048
  0.40464682  0.28559707  0.50437368  0.62452755  0.6260493   0.8655808
  0.17807104  0.18681972  0.04155728  0.56806908  0.94850833  0.24370249
  0.35765483  0.89433325  0.07559579  0.61454663  0.13842277  0.65972417
  0.73097187  0.84573058  0.7950438   0.15670343  0.61815017  0.32094016
  0.80130902  0.83504488  0.54375348  0.61431943  0.09143887  0.04277234
  0.65524544  0.60111505  0.66263407  0.76344574  0.83502803  0.94134082
  0.26084356  0.35749763  0.62763195  0.81178929  0.48528719  0.13671454
  0.0176141   0.99391563  0.34881976  0.7254549   0.46949537  0.53922582
  0.38198053  0.65606638  0.72354593  0.53670509  0.90203879  0.90227833
  0.97482979  0.61325619  0.69560875  0.27526231  0.69411601  0.96786676
  0.99509535  0.84992818  0.72699099  0.03967448  0.98071572  0.64435258
  0.62374842  0.94325358  0.45106579  0.44398332  0.04354132  0.5004252
  0.79682657  0.91149797  0.01555657  0.39608579  0.02458729  0.45885217
  0.94559807  0.21777187  0.51090057  0.7490105   0.06490062  0.88134888
  0.15604393  0.85243401  0.09029304  0.27969706  0.24828555  0.26724126
  0.65959536  0.15867794  0.73060841  0.77933186  0.64109054  0.657582
  0.82405681  0.41304716  0.22169958  0.16409366  0.25087268  0.93836482
  0.3794331   0.57535451  0.41982761  0.25098015  0.18436689  0.26874191
  0.55104832  0.24728295  0.52594757  0.94835012  0.81756657  0.92362064
  0.40263214  0.46886778  0.70909609  0.77773609  0.2633769   0.88004827
  0.83284854  0.60903114  0.82424423  0.14680197  0.31279527  0.79644269
  0.26312324  0.48511083  0.67817007  0.41746739  0.39592033  0.25822536
  0.32734166  0.66065028  0.27672177  0.54988815  0.55318284  0.26892011
  0.52637405  0.35549521  0.41509832  0.57365106  0.3511396   0.31520375
  0.00789935  0.46036226  0.04087971  0.3366892   0.24268356  0.81863641
  0.88605343  0.42223618  0.8767516   0.62803093  0.8786011   0.13812166
  0.83668774  0.22794624  0.49877921  0.11185059  0.75341717  0.30365766
  0.42309361  0.14585565  0.07402537  0.74119257  0.86230909  0.77097799
  0.83667396  0.10784606  0.65185664  0.07275117  0.32038686  0.6256068
  0.18483113  0.1359349   0.96109215  0.76013654  0.01520697  0.33330081
  0.26524175  0.95352493  0.33187299  0.68235104  0.63830335  0.96634333
  0.97960171  0.36660547  0.88873263  0.05122451  0.86075176  0.42233638
  0.94934587  0.16900798  0.5760227   0.77984522  0.33308808  0.76861907
  0.7038735   0.85847884  0.95432613  0.70633757  0.64936431  0.43423621
  0.08143045  0.05798729  0.82160863  0.31602944  0.89507038  0.00732103
  0.60145943  0.83095382  0.09573175  0.51334012  0.58692229  0.33200005
  0.24265952  0.89418771  0.27611654  0.74974361]
1.0

In [78]:
# Does choice return a good distribution over a large number of runs?

In [247]:
%%file many_choice_runs.py
# -*- coding: ascii -*-
""" Exploring unit tests.
    Simple code to implement a simple Markov transition function.
    And test it over many runs for even distribution.
    
"""
__author__ = "Mike McFarlane (mike@mikemcfarlane.co.uk)"
__version__ = "$Revision: 0 $"
__date__ = "$Date: 14-04-14"
__copyright__ =  "Copyright (c) Mike McFarlane 2014"
__license__ = "TBC"

import random
import numpy as np
import custom_exceptions as ce

def choice2(inArray):
    """ Simple function to implement a Markov transition function.

    """
    randNum = np.random.random()
    cum = 0
    sumVal = np.sum(inArray)
    if not abs(sumVal - 1.0) < 1e-10:
        #print "not a P array"
        raise ce.MatrixError("Not a valid array")
    else:
        for count, i in enumerate(inArray):
            cum += i
            if cum >= randNum:                
                return count
            
def main():
    numRuns = 1000000
    transitionMatrix = np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
    # Run choice function many times.
    list = [choice2(transitionMatrix) for i in range(numRuns)]
    # Generate histogram of result.
    listHistogram, listBins = np.histogram(list)
    print "listHistogram: ", listHistogram
    #print "bins: ", listBins
    listPercentage = [(x / float(numRuns))*100 for x in listHistogram]
    print listPercentage
    print np.sum(listPercentage)
            
if __name__ == '__main__':
    main()


Overwriting many_choice_runs.py

In [248]:
!python many_choice_runs.py


listHistogram:  [ 99634 100058 100231 100286 100018 100131 100202  99635  99595 100210]
[9.9634, 10.005799999999999, 10.023099999999999, 10.028600000000001, 10.001799999999999, 10.0131, 10.020199999999999, 9.9634999999999998, 9.9595000000000002, 10.020999999999999]
100.0

In [249]:
# Run code in ipnb for plot
import random
import numpy as np
import matplotlib.pyplot as plt

def choice2(inArray):
    """ Simple function to implement a Markov transition function.

    """
    randNum = np.random.random()
    cum = 0
    sumVal = np.sum(inArray)
    if not abs(sumVal - 1.0) < 1e-10:
        #print "not a P array"
        raise ce.MatrixError("Not a valid array")
    else:
        for count, i in enumerate(inArray):
            cum += i
            if cum >= randNum:                
                return count
            
def main():
    numRuns = 1000000
    transitionMatrix = np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
    # Run choice function many times.
    list = [choice2(transitionMatrix) for i in range(numRuns)]
    # Generate histogram of result.
    listHistogram, listBins = np.histogram(list)
    print "listHistogram: ", listHistogram
    listPercentage = [(x / float(numRuns)) * 100 for x in listHistogram]
    print listPercentage
    
    
    plt.plot(listPercentage)
    plt.axis([0, 9, 0, 12])        

main()


listHistogram:  [100107 100169 100525 100151  99767  99763 100282  99719  99447 100070]
[10.0107, 10.0169, 10.0525, 10.0151, 9.9766999999999992, 9.9763000000000002, 10.0282, 9.9718999999999998, 9.9446999999999992, 10.007000000000001]

Conclusions

  1. Unit tests will allow me to refactor code and ensure it works.
  2. Unit tests can be highly structured into classes, but are perhaps just as effective as a list of single test methods.
  3. At my level I see no difference between unittests and nose.
  4. Running unit tests is significantly slower (approx 1sec for 4 tests vs 0.0002s) if a broker is created to NAO in each setUp() and stopped in each tearDown().
  5. The fastest approach appears to be to create a global variable instance as is normal in NAO code and to create and destroy the broker only once in the whole test. It is possible in more complex method tests that this may cause problems with shared variables.
  6. I spent about 4 hours trying to get the unittests to run in the NAO robot code as I renamed the test methods from the initial development code. Test methods names need to start with the word 'test'. If I had carefully re-read the documentation at http://docs.python.org/2/library/unittest.html I would have solved this more quickly.
  7. Stackoverflow is great, but keep questions concise.

Next steps

  1. Keep unit tests maintained and running them for TickleMeNAO app.
  2. At a later date investigate nose as it is popular framework.

In [ ]: