Posts Tagged ‘test’

Python Package Structure with Unit Testing, Injection and Mocking

7 Comments »

Python is a language that some people like and use.  I recently was given a small Python application and had to refactor it so that I could implement unit and functional tests.  It took me a while to find the resources and learn how to implement them, so I thought I’d write it up here.

* Please note that this is not a unit testing tutorial.  Those are plentiful and can be found elsewhere.  This describes setting up a professional Python project with a real package structure, injection and tests.

Python Project Structure

Python was conceived as a scripting language.  Unlike compiled languages like C or Java, Python files are designed to be directly runnable.

  • RunMe.java -p someargument < Not ok!
  • RunMe.py -p someargument < Ok!

This is convenient for small scripts, but doesn’t help applications.  Since you are intended to run .py files directly, Python projects should not have source (src) or binary (bin) folders.  Having a source folder makes a program difficult to run.  The root of the Python package structure should be the root of the project.

For the same reason, the test folder should not be separate.  It should be a package in the main project.  Since the root folder is the root package, you won’t have much choice.

Example

  • MyProject
    • __init__.py
    • model
      • __init__.py
      • user.py
    • service
      • __init__.py
      • user_service.py
      • ldap_user_service.py
    • test
      • __init__.py
      • unit
        • __init__.py
        • service
          • __init__.py
          • user_service_test.py
      • functional
        • __init__.py
        • service
          • __init__.py
          • user_service_test.py

If you’re new to Python, please note that those __init__.pys are required.  They tell Python which folders contain Python files.  This is Python’s way of allowing you to have other folders, such as config, that don’t contain source files.

Note

You should specify exactly one class per file.  It makes your code easier to find and read.

Injection with snake-guice

Injection is essential for unit tests.  In the example above, LDAPUserService may connect to an LDAP server to retrieve information, something we don’t want to happen in unit tests.

I’ve been using snake-guice and highly recommend it.

Install snake-guice, Mock and nose

If you don’t have it, grab a copy of easy install.  Then, $ sudo easy_install.py snake-guice Mock nose.  That installs packages from PyPI, the Python Package Index.  For those used to non-scripting languages, this may not seem like a great way to use external libraries.  Since Python is a scripting language, however, it’s the only way that makes sense.

Create a module and use it to instantiate your application

class ExampleModule:
  def configure(self, binder)
    binder.bind(UserService, to=LDAPUserService)
class ExampleRunner:
  user_service = None
 
  @inject(user_service=UserService)
  def __init__(self, user_service):
    self.user_service = user_service
 
  def main(user_service)
    self.user_service.login("name", "password")
injector = Injector(ExampleModule)
runner = injector.get_instance(ExampleRunner)

When get_instance is called, injector will use the ExampleModule to discover bindings.  Then, it will create an ExampleRunner, passing in arguments specified by @inject.

The setUp method of PyUnit tests should create an injector with a TestExampleModule, which should be configured to return mocks.

class TestExampleModule:
  def user_service = Mock()
 
  def configure(self, binder)
    binder.bind(UserService, to=user_service)
class ExampleTest(TestCase):
  application = None
 
  def setUp(self):
    Injector = Injector(TestExampleModule)
    self.application = injector.get_instance(ExampleApplication)
 
  def test_something(self):
    application.user_service.search.return_value = "expected"
    actual = application.user_service.search("any")
    self.assertEquals(expected, actual)

Since setUp is called before each test, each test method gets a fresh mock that it can configure any way it likes.

Similarly, a functional test module can be created that connects to a local or testing server.

Mocking with Mock

I recommend using Mock for mocking, which is why I had you install it earlier.  Be careful when searching for it because there appear to be two projects called Mock.

The Mock package is well documented.  Please go to the Mock site for more information.

Running Tests

For running tests, I recommend Nose.  To run your tests, open a command line and change to your root project folder.  Then, nosetests.  Nose will take care of adding the packages you installed earlier, snake-guice and Mock, to the Python path.  It will also find all tests, run them and report the results.  Handy!

$ cd ~/exampleproject
$ nosetests

To run only unit or functional tests, use the -w argument.

$ nosetests -w ./ ./test/unit
$ nosetests -w ./ ./test/functional

Is that all?

To those who have not used injection or mocks for testing, this may seem like a lot of work.  I hope you’ll try it, though, because it’s a one-time setup.  Once these good practices are in place, you’ll find that all of your code organization and testing becomes simple and almost automatic.  If I missed something or if you have any suggestions, please post below.


Testing in Android with mock UI components

1 Comment »

As described in an earlier post, Android is not friendly to mocking frameworks or mock-style testing.  If you want to test any class in your application that deals with the Android API, it’s best to run your tests through the emulator, accessing real Android classes.  It’s unfortunate because you’re not just testing your application.  You’re also testing Android.  Anyway, here’s a way to mock a UI component.

If you’re just starting, here are a couple notes to keep you on the right track.

  • Android is bundled with JUnit 3.  Don’t try using an updated JUnit library or another testing framework.  The Android jar doesn’t contain any functional code, so all test cases have to be run in the emulator, which uses JUnit 3.  The test framework that will work best is in the Android API.
  • If you need basic implementations of Android classes, try to avoid mocking them.

“Mock”ing

In my latest test, I needed a TextView so that I could call the simplest method, setText(String).  I’ll describe how I got one.

Don’t bother with the android.test.mock package.  It just contains implementations of classes that throw UnsupportedOperationExceptions.  There isn’t anything there that I have yet found useful.

  1. In the test case, instead of extending TestCase, extend at InstrumentationTestCase or, if necessary, one of its subclasses.  It’ll set up most of the stuff that’s available in an Activity and make it available to your test case.
    public class AnAndroidTest extends InstrumentationTestCase {
  2. Create a mock implementation of TextView or the class you need.
    public class MockTextView extends TextView {
      public MockTextView(final Context context) {
        super(context);
      }
    }
  3. The TextView constructor needs a real Context object because it will call methods on it.  The context is difficult to mock because parts of it are private to Android.  Since the Android JAR is just an API and doesn’t have any functional code, you couldn’t even see the methods if you tried.  They only exist in the VM in the emulator.  AFAIK, if you can’t see a method, you can’t mock it.  That’s why your test case extends InstrumentationTestCase.  Put this in it.
    final TextView textView = new MockTextView(this.getInstrumentation().getContext());

Now write the test case.  The text view is real and has a fully functional context, so the emulator will have everything it needs to support your test case.