Cocoa unit testing with OCUnit and OCMock: Mocking out IBOutlets

June 27th, 2009

I’ve been doing Objective-C (Cocoa) development for OS X at work now for just under a month, and I’m probably going to start pasting some useful snippets here on the blog.

One thing that I had some issues getting to work when I started writing unit tests for my code was IBOutlets for objects that were instantiated through the interface builder. These will only have their bindings setup when initializing the class with loadNibNamed from NSBundle or something similar. This is a bad idea during unit tests since it makes your tests depend on other classes. It is also rather slow.

Instead it’s better to just inject the IBOutlets manually.

The starting point

Let’s pretend I have a class called GameEngine whose interface and implementation looks something like this.

// GameEngine.h
@interface GameEngine : NSObject
    {
        // Handled by interface builder bindings.
        IBOutlet EnemyManager *enemyManager;
    }
    - (void)updateEnemies;
@end
// GameEngine.m
@implementation GameEngine
    - (void)updateEnemies
    {
        [enemyManager update];
    }
@end

If I were to test updateEnemies, I would have to detect if update was called for the enemyManager. If I just initate a GameEngine in my tests like the example below, enemyManager will not be hooked up (due to the lack of reference to the nib file which hooks up the bindings). This means that there’s no way to see what actually goes on inside the class.

One might think that this could be an issue, but it’s actually quite nice once you apply some additional test code.

Injecting the IBOutlet bound object

To setup you IBOutlets in your tests, you simply have to add an additional initializer as a category in your test code. This wont expose any additional initializer in the classes API outside of the tests, and it will allow you to replace the outlet bindings with mocks.

// GameEngineTestCases.m
@interface GameEngine (testing)
    - (id)initWithEnemyManager:(EnemyManager*)manager;
@end 

@implementation GameEngine (testing)
    - (id)initWithEnemyManager:(EnemyManager*)manager
    {
        self = [self init];
        enemyManager = manager;
        return self;
    }
@end

@implementation GameEngineTestCases
    - (void)testUpdateEnemies
    {
        id mockEnemyManager = [OCMockObject mockForClass:[EnemyManager class]];
        [[mockEnemyManager expect] update];
        GameEngine *engine = [[GameEngine alloc] initWithEnemyManager:mockEnemyManager];
        [engine updateEnemies];
        [mockEnemyManager verify];
    }
@end

Now you’re safely able to test your class without having to worry about nib files or external classes.

buffi Uninteresting

CVS is cute

June 21st, 2009

I played around a bit with Wireshark yesterday, and the initial server response when connecting to a CVS server is pretty cute.

CVS is cute

Unfortunately I’m guessing that nobody loves CVS anymore…

buffi Uninteresting

Job GET! (and some short book reviews)

May 17th, 2009

Like I mentioned in a previous post, I got my Master’s degree earlier this year. Since then I’ve been taking some courses at the University while looking for a nice place to work. In other words, I’ve mostly been slacking around :)

About two months ago I decided to browse through a Swedish job database and found an opening as a programmer at Interactive Institute: Sonic Studio which seemed quite cool. I sent in my CV, went on some interviews and finally signed the hiring papers about 1-2 weeks ago. My first day on the job is about a week from now, and I’m really looking forward to it.

Since Sonic Studio is positioned in Piteå which is about 50km from Luleå (where I live) by car, I’m currently browsing for a decent used car to purchase. This sucks quite a lot since my knowledge in cars is pretty much limited to knowing where the motors and wheels are positioned, but hopefully I’ll be able to work this out since the other option is taking the bus which leaves me with about thirty less minutes sleep in the mornings.

Otherwise I’ve done a bunch of small stuff during the latest months. Among other things, I started coding on a game-engine for shoot-em-up development since I’ve been wanting to build one of those for some time, and I felt the need to brush up on my C++ after doing a bunch of Java and Python development. This is pretty much just a pet-project that I’ve been playing around with occasionally when I get bored, an early proof of concept video is available here in case someone would be interested in that.

I’ve also been reading a bunch of nerd-literature. Since I’ve played around a bit with C++ again, I finally decided to read through Thinking in C++ which helped me brush up on my syntax, among other things. In my opinion, it is a pretty great book for learning and improving ones skills in C++ but I haven’t really read any other books about the language to compare it to.

When I finished up that book, I started with The Pragmatic Programmer which has been on my “to read list” for some time. The book is essentially a list of tips for developing software, where some of them might seem obvious but others actually forces you to rethink your development process. One of them which I know that I’ve made myself guilty of occasionally is the tip they call “Leave no broken windows”. The real world example given in the book is a car that is left in the streets. The car can be left alone for quite some time but once the first window is destroyed, the rest of the car is usually plundered and vandalized within a short span of time. The same hold true for software, and I have personally ignored small bugs to find them come back with friends later on to torture me. Once you start compromising your code quality, it usually snowballs and gets worse quite fast.

It touches a lot on the non-programming aspects of development as well, such as making sure that you gather the correct requirements for you project and use proper tools such as revision control. Of course there are a lot of other great tips in the book as well, and I’d recommend it to pretty much anyone who are involved with development of software.

Finally I’ve read a new book on lighttpd. As I’ve written previously in the blog, I’ve migrated most of my web-stuff from Apache to lighttpd and I couldn’t be more pleased. Setting up lighttpd is a lot easier than setting up Apache, so you wont really need a book for it but I’d definitely recommend it to anyone who either wants a good guide for setting it all up or just tuning an existing installation. It covers a wide arrange of topics including setup, encryption, DOS-protection and migration from other web servers. All in all, it isn’t an essential book for anyone who wants to run an lighttpd-installation but I’d recommend it since it beats the online resources in readability.

buffi Programming & scripting, Python, Uninteresting, Web development , , ,

A nasty bug

April 27th, 2009

A few weeks ago a pretty nasty bug appeared on my image hosting service pici.se about a month ago. For some reason, some people started noticing that their thumbnails were changed to pictures which didn’t belong to them. This was a rather serious issue, and I had a look at the code to figure out what was going on. I realized that I had recently changed my deployment from Django under apache to Django under lighttpd and this was surely related to that… but how?

It turned out that it was a combination of bugs that together fucked stuff up for me pretty bad. Since I started allowing pictures over 1MB a while ago, but wanted to limit hotlinking to them, I put them into a separate directory from the other pictures being served. That meant that the large pictures were given filenames such as “large/asSDavXZ.jpg” instead of “asSDavXZ.jpg” where the filename is randomly generated. I had however forgotten to update my code to check for the presence of these images when fetching a new random file name, that is my code looked something like this (pseudo-code):

filename = get_random_stuff()
while file_exists(filename):
  filename = get_random_stuff()

when it should have been changed to this:

filename = get_random_stuff()
while file_exists(filename) or file_exists("large/" + filename):
  filename = get_random_stuff()

When I saw this, the first thing that came to mind was that this shouldn’t be such a big deal. Generating two filenames which were the same should pretty much never happen since there are so many possible combinations of characters.

Well… it did. And quite often. Running some scripts on the server showed that there were quite a lot of these collisions which seemed REALLY weird, and then I found this bug in Django. It seems like fastCGI deployment using method=prefork gives the same random seeds to each process. In combination with my fuckup, this made these collisions happen quite a lot and people got their thumbnails overwritten since all thumbnails were stored in the same folder without the “large/” prefix for each image.

That is, for a pictures thumbnail to be overwritten the following had to happen:

1. Someone uploads a picture below 1MB and is handed to fastCGI process 1 and given a “random” string for it’s filename.
2. Someone else uploads a picture larger than 1MB and is handed to fastCGI process 2, and given the same randomized string as a filename due to the random seeds being non-random due to a bug in Django.
3. My code has a nasty bug in it and doesn’t detect this collision.
4. Thumbnails are generated for image2 at the same target as the thumbs for image1.

Fixing the bug in my code was rather trivial but I also patched my Django installation to avoid any other weird issues due to non-random seeds. The current patch which is available for the bug should however not be utilized since it uses time.ctime() as a random seed for each request, and ctime() will only change once a second which means that subsequent requests given to the same fastCGI process during the same second will be given the same seed. Instead time.time would be better, so I patched my installation with pretty much the same thing but using the following instead.

random.seed("%d%f" % (getpid(), time())) 

This seems to generate random values for each request as far as my testing goes.

buffi Programming & scripting, Python, Web development , , , ,

Migrating Django from Apache to lighttpd using FastCGI

February 3rd, 2009

I run a medium traffic imagehosting site which serves about 8-10000 pageviews per day using Django and I have been using the recommended deployment method (Apache + mod_python) for just under two years and it has mostly worked well. However, about two months ago I was starting to notice increasing delays from the server and Apache would occasionally fail in spectacular ways which brought the CPU load to 100% for long periods of time.

I have always used lighttpd to serve static content, and since I don’t really enjoy the Apache configuration syntax I decided to give the lighttpd + FastCGI deployment method a try. I expected this migration to be complicated, but it took me less than an hour to figure it out. I have some minor documentation of my changes below in case you are interested in the basics of how to handle a Apache -> lighttpd Django migration.

Apache configuration

My old configuration, using Apache looked like this (some stuff omitted).

<VirtualHost *>
        ServerName pici.se
        DocumentRoot /var/www
        ErrorLog /var/log/apache2/pici_error.log
        ServerAlias pici
        <Location "/">
            PythonPath "['/home/buffi/site'] + sys.path"
            SetHandler python-program
            PythonHandler django.core.handlers.modpython
            SetEnv DJANGO_SETTINGS_MODULE pici.settings
            PythonDebug On
        </Location>
        <Location "/css/"> SetHandler None </Location>
        <Location "/js/"> SetHandler None </Location>
        <Location "/im/"> SetHandler None </Location>
        <Location "/picisendfiles/"> SetHandler None </Location>
        <Location "/pictures/"> SetHandler None </Location>
        <Location "/thumbs/"> SetHandler None </Location>

        # Static content served with lighttpd.
        RewriteEngine on
        RewriteRule  ^/pictures(.*) http://static.pici.se:8080/pictures$1
        RewriteRule  ^/thumbs(.*) http://static.pici.se:8080/thumbs$1
</VirtualHost>

lighttpd configuration

The corresponding lighttpd configuration became:

$HTTP["host"] =~ "pici\.se" {
    server.document-root = "/home/buffi/site/pici/"
    fastcgi.server = (
        "/pici.fcgi" => (
            "main" => (
                "socket" => "/home/buffi/site/pici/pici.sock",
                "check-local" => "disable",
            )
        ),
    )

    alias.url = (
        "/css/" => "/home/buffi/site/pici/picipage/css/",
        "/js/" => "/home/buffi/site/pici/picipage/js/",
        "/im/" => "/home/buffi/site/pici/picipage/im/",
        "/thumbs/" => "/var/www/static/thumbs/",
        "/pictures/" => "/var/www/static/pictures/",
        "/picisendfiles/" => "/var/www/picisendfiles/",
       )

    url.rewrite-once = (
        "^(/css.*)$" => "$1",
        "^(/im.*)$" => "$1",
        "^(/js.*)$" => "$1",
        "^(/picisendfiles.*)$" => "$1",
        "^(/thumbs.*)$" => "$1",
        "^(/pictures.*)$" => "$1",
        "^(/.*)$" => "/pici.fcgi$1",
        )
}

You might notice the path of a FastCGI socket.

“socket” => “/home/buffi/site/pici/pici.sock”,

To create this socket, simply use the FastCGI script available through manage.py. I create my socket using the following command.

./manage.py runfcgi method=prefork socket=/home/buffi/site/pici/pici.sock pidfile=pici.pid

All Django requests will then be forwarded from lighttpd to the FastCGI daemon.

Conclusion

By migrating from Apache to lighttpd I noticed a nice performance boost and got a more enjoyable syntax for my configuration. I haven’t really bothered to measure the decrease in CPU load, but it is easily noticeable and my server doesn’t become as sluggish as before during heavy load. I’ve used lighttpd + FastCGI for about a month or so now, and everything seems stable. I’d recommend any Django developer using Apache to give it a try.

buffi Programming & scripting, Python, Web development , , , ,

College Degree GET!

February 2nd, 2009

I got my degree today (Master of Science in Computer Science and Engineering).

Master's Degree in Computer Science and Engineering

buffi Uninteresting

Google is broken

January 31st, 2009

Google = broken

Apparently I’m harmful for your computer.

buffi Uninteresting

Update! (TL;DR warning)

January 29th, 2009

I haven’t posted anything on the blog in close to a year, but I’m in the mood to start blogging a bit again so I guess I’ll post an update on what I’ve been doing since last year.

I got engaged to my girlfriend Li in May last year, and we moved into a new apartment some time around July (if I remember correctly). It is about the same size as the one we lived in earlier, but it looks a lot nicer and is in a better neighborhood, within walking distance of central Luleå. Some pictures of the new place below:

In June I started working on my Master’s Thesis as an intern at Google in Luleå. I worked together with the Gmail voice and video chat team for six months, and it was an awesome experience which I would recommend to anyone. I learned a LOT during these months and I’m pretty sure that it would be close to impossible to find a better place to perform an internship as a CS student. Unfortunately, in January (about a month after the end of my internship) Google announced that they are closing the Luleå office which is a shame. I guess that it isn’t very cost-effective for Google to keep around small offices like this, but it was in my opinion an awesome office with very talented people and I feel privileged to have been able to perform my Thesis there while it was still around.

Since the end of my internship I’ve been waiting for the administrative personal at my University to finalize my graduation papers, and I will apparently receive them in about a week which makes my a MASTER OF SCIENCE (which unfortunately isn’t quite as awesome as it sounds). Since I will graduate that means that I will have to start looking for work… and yeah, graduating right in the middle of a “financial crisis” isn’t really timed very well :( .

I’m currently mostly looking for jobs around Luleå since I really like it here, but I guess that I’m not completely against relocating if I have to (it beats going unemployed). For now I’m reading some extra courses (tuition is free in Sweden, and we actually receive money for studying here unlike those silly Americans who have to pay for everything) and working my old part-time job as an IT admin at the University. At least that leaves me with a bunch of spare time.

Except for all that I haven’t really been up to a whole lot. I’ve been playing a whole lot of video games, since October-November 2008 was pretty insane with a bunch of great releases. Since I had a bunch of free time at the end of the year I ended up playing through Dead Space, Mirrors Edge, Valkyria Chronicles, Fallout 3, Prince of Persia, Fable 2, Little Big Planet, Gears of War 2 and probably a bunch of other stuff that I’ve forgotten about… and that’s just counting retail games. I’ve played PSN games like crazy as well and I’ve maxed out a whole bunch of games including Astro Tripper, Lumines Supernova and Minna no Putter Golf with Toro.

In December I also purchased my first DSLR camera, a Nikon D40. Photography seems interesting, but I’m still pretty shitty at it. It’s nice to have a decent camera to play around with though. If I manage to snap something decent I might post it in the blog.

My current courses aren’t really that challenging and I’m currently only working about eight hours or so per week, so in the nearest future I’ll most likely continue looking for nice jobs, hammer away at some software projects I have ideas for and play a shitload of video games since Street Fighter 4, Killzone 2 and Resident Evil 5 is right around the corner.

Hopefully I’ll have time to update this blog more often as well (if anyone actually reads it).

edit: Oh yeah, I traveled to Amsterdam and Zürich during the summer as well. Amsterdam was a lot nicer than Zürich.

buffi Uninteresting

Whoa, Echochrome has level sharing between users!

March 31st, 2008

This post isn’t about programming for once. I also tend to spend a lot of time in front of my PS3 and just found out something that is quite cool and seems to have been overlooked.

Echochrome has been out in the Japanese and Hong Kong store for a little while now, and apparently it supports level sharing! And not just that, but it uses your PSN friends list as well (you can also send levels to people who aren’t your friends). There is also a feature for “uploading to a public server” but I couldn’t get that to work. Anyways, I really like this step towards community driven content, and I hope more games will use it. Here are some pictures:

The “Factory” for custom levels:

A test level I made just to try it out:

The send-dialog box:

Ingame friends list:

Sending…:

Transmission completed!:

Unfortunately Echochrome is scheduled for May outside of Asia, which is weird as hell considering that the version from the Hong Kong store is completely in English. There doesn’t seem to be any limitations for purchasing it for users outside of Hong Kong (I’m located in Europe) so there really doesn’t exist any reason to wait. Get a HK-account and download it now :)

buffi Gaming, Gaming Software

One of the main reasons that so many PHP-coders suck at programming?

February 2nd, 2008

I was about to just write a very small thing in PHP, and wondered what the nicest way to get a random string i PHP would be (lacking a nice sample method like in python) and googled “random string php”.

I found this.

Just… what is that? It just might be the ugliest piece of code I’ve ever seen. Not only does it have a nice little switch statement for each letter in the alphabet, for some reason the coder also seeds the random seed for each iteration in the loop.

This might be the worst I’ve seen, but I’ve seen a lot of PHP example code that is pretty close, and I think that this might be one of the main reasons that a lot of PHP-developers produce unreadable code (have a look at tbsource among other large projects for some horrifying code).

It’s nice that people like to share their code to teach others, but you are more likely to hurt development if you don’t have a clue what you are doing.

I’m not saying that all PHP-developers are horrible programmers (because they aren’t), and I use quite a few PHP-applications myself (such as wordpress) but the ratio of bad code compared to other languages seems to be way above average.

buffi Programming & scripting