Geeks With Blogs

News

Series

Add to Technorati Favorites


An Archived Managed World This blog has moved to http://www.managed-world.com/blog

Lately, I've been spending some private time learning Python. It is definitely a different beast than C#. For one, it has taken a little while to get used to the dynamicism of Python compared to C#. Now, don't get me wrong, I'm still in love with C#, I just am falling in love with certain aspects of the Python language. And, well, I'm going to blog about it here because I don't really have any one to share this with at the moment and I need to get it off my chest.

I just had my first “OH SHIT!” moment in Python. Before I describe that though, a little background to what I've been trying to do with unit testing lately. I've been thinking a lot about mock objects. What I wanted was an easy way to intercept any call to a given class at runtime and redirect it to a mock object. For instance, if class Foo creates an instance of class Bar, I want to say that any future method call to anything in Bar should be redirected to my class MockBar. Now, there are easy ways to solve this issue for most circumstances. For example, passing an IBar object to the method call or to the Foo class constructor is an option most of the time. But, there are times where this can lead to code and APIs that aren't perhaps the most usable APIs.

Usually, it requires a little give and take. Code that is really testable isn't necessarily the most intuitive to use. You have to compromise (I'm talking generally here). As with many other things, it is something where you have to choose which side to design for. For instance, highly performant code isn't necessarily the easiest code to read. On the other hand, code that is really easy to read isn't necessarily the most performant. At times, it's the same with testability and usability, I believe. You may believe otherwise of course, but that doesn't mean you're right :P. Of course, there are exceptions to everything I'm saying here :).

Okay, with that out of the way, on to the moment I had just now. Since Python is a dynamic language, and everything is considered an object (even function and class definitions themselves), we can automatically alias our mock objects to test our code. As an example, let's take a small example. First, we will just alias a function definition. Here is a small snippet of code that has a method that we may want to mock. Here is the pre-mocked version:

>>> class Foo:
...      def bar(self):
...              print 'Hello from boring bar'
...                
>>> myFoo = Foo()
>>> myFoo.bar()
Hello from boring bar

To mock this, we simply need to define a new mock function and re-alias the bar function to point to our mock function. Here's how it might look (and you can see the output):

>>> def mockBar(self):
...        print 'Hello from mockBar, baby!!!'
...
>>> Foo.bar = mockBar  #<-- Alias the bar definition in class foo to our new mockBar function
>>> myFoo.bar()
Hello from mockBar, baby!!!

That is extremely cool! And it just doesn't stop with functions. You can do the same aliasing at the class level. Remember, EVERYTHING is an object in Python, even class and method declarations. Check it out:

>>> class Foo:
...         def myMethod(self):
...                 myBar = Bar()
...                 myBar.sayHello()
...                 
>>> class Bar:
...         def sayHello(self):
...                 print 'Hello from boring Bar'
...                 
>>> myFoo = Foo()
>>> myFoo.myMethod()
Hello from boring Bar
>>>
>>> class MockBar:
...         def sayHello(self):
...                 print 'Hello from MockBar, Baby!!!!'
...                 
>>> #Alias Bar class now
>>> Bar = MockBar
>>>
>>> #Retest myMethod()
>>> myFoo.myMethod()
Hello from MockBar, Baby!!!!

I love this language!

Now, there is a method to do something very similar to this with C# using context-bound objects and switching the context at runtime. However, you have to realize that there is overhead involved in making an object and context-bound object. Also, since multiple inheritance is not possible in .NET, sometimes making an object a context-bound object just isn't possible.

One thing is for sure, I'm sure this love affair isn't over. However, it's not all bright and cheery. There are some things that I have found that I don't like in Python. I think that a lot of those though are simply because I've been so used to using statically-typed languages. Time will tell, and I'm sure you all will hear more about it as time passes.

NOTE: This doesn't mean that you will automatically write good tests by having this tool available to you. Also, I would say that you should try not to use this testing method every time either. There are better ways to test your code. However, in those situations where other roads aren't available, this could be a life saver (or so I imagine, since I actually haven't been able to use it in a production environment yet).

Posted on Saturday, February 19, 2005 9:15 PM | Back to top


Comments on this post: Falling In Love With Python

# re: Falling In Love With Python
Requesting Gravatar...
What happens if you want to test code that is already using these language features though?

I'm also still in the early stages of learning Python. (In particular, I've still only played with it - I've not yet built anything real with it.) But I've seen lots of examples showing interesting tricks based on exactly the techniques you show here.

What I wonder is how well they compose.

Now for unit testing it's not that big a deal - you'll discover the problem early on. And if you wanted to use this technique both in the code being tested and the test itself, you'd be forced to make sure that the test and testee play nicely. But what I worry about is using this sort of technique in shared code such as a library, or a framework.

My gut reaction is that this sort of thing is just great if you're the only developer working on the code that uses it. But I'd anticipate trouble if you were building something larger scale.
Left by Ian Griffiths on Feb 21, 2005 6:31 AM

# re: Falling In Love With Python
Requesting Gravatar...
I'm with you Ian. I honestly see it as a confusing feature to use if you're using it in your shared library code. I would imagine there would be better ways to get it done while still having the code be readability. I can only imagine that debugging code that uses these features would be more difficult, or cause a little more pain.

I was thinking of it merely from a unit testing perspective. I think in some situations for unit testing, it would come in really handy. But on a wider scale, it seems like you should try to avoid this kind of code if possible. Of course, I could just not be seeing the whole picture on these features though due to my lack of Python experience.
Left by Jason Olson on Feb 21, 2005 1:26 PM

# re: Falling In Love With Python
Requesting Gravatar...
If you think Python is cool, check out Objective C. You're gonna crap your pants :) For a start, read this article and forget about Python.

http://www.stepwise.com/Articles/Technical/PosersAndCategories/
Left by Stoyan on Feb 24, 2005 4:49 AM

# re: Falling In Love With Python
Requesting Gravatar...
Whoa, why you learning a new language? We're all counting on your Managed DirectX tutorials!
Left by Ron on Feb 24, 2005 10:03 AM

# re: Falling In Love With Python
Requesting Gravatar...
Yeah, I would really love it if there would be some way you could whip up a couple of Managed DirectX examples in boo.

Boo is just like python but it runs as fast as any C# program since it has static typing. So it would be a great option for game development.
Left by NH on Feb 26, 2005 1:04 AM

# re: Falling In Love With Python
Requesting Gravatar...
On the other side of the CLI/Python thing - you can use Python to call .Net code with this:

http://www.zope.org/Members/Brian/PythonNet/README.html

I haven't tried it with any managed directx stuff, but the windows.forms stuff works straight out of the box.

And as for boo - 'it's like a non-dynamic python' means it's not like python. IMO anyway ;)

As for speed? Don't buy into the 'Python is slow' thing - _most_ real (game or otherwise) development can happily live in the world of Py, calling out to optimised code as/when required. 95% of the work will be in 5% of your code. Yadda yadda.

Personally I'd like the remaining 95% of my code to be in a Python :)

</overzealous python defending>
Left by Dom on Mar 16, 2005 4:31 AM

# New Year, New Skills (UPDATE)
Requesting Gravatar...
A while back (just after the New Year), I talked about my programming goals for this year. Always looking to expand my skillset, I jumped on the Python bandwagon that so many .NET developers are riding on these days. I have to admit, Python is cool. My initial reaction to...
Left by XML-BLOG on Mar 30, 2005 5:04 PM

# re: Falling In Love With Python
Requesting Gravatar...
On the objective-c note, there is a great mock objects framework called OCMock:

http://www.mulle-kybernetik.com/software/OCMock/

If you look at the source code, you can see that objective-c's dynamic features make creating a mock object framework trivial relative to other languages....
Left by Grim on Mar 30, 2005 7:04 PM

# re: Falling In Love With Python
Requesting Gravatar...
Everything in Python is 'not' an object
Left by Gruk on Nov 04, 2009 5:14 PM

Your comment:
 (will show your gravatar)


Copyright © Jason Olson | Powered by: GeeksWithBlogs.net