Producing Better Bindings for Xamarin.iOS and Xamarin.Mac

Sebastien Pouliot

For .NET developers with some knowledge of Objective-C, writing .NET bindings for Objective-C libraries is not very hard. It is well documented and several complete examples are available to guide you.

Still, the process can be quite error-prone. Many typos and mistakes will only be caught at runtime and only when you use the specific API affected. Due to those issues, many bugs won’t be found for days, months or even years after you released your bindings.

Full test coverage would considerably reduce the number of bugs—but it would require 2x-5x time to create the bindings. That might not be the best way to invest your time into a project. Fortunately, the Objective-C runtime has introspection APIs available, even if limited compared to .NET. That makes it possible to run generalized test cases without knowing the purpose for which the bindings were intended.

This blog series will go through different test fixtures to help test Xamarin.iOS or Xamarin.Mac Objective-C bindings. With a bit of customization (you need to inherit from them and override a few methods) you will be able to spot some of the most common binding mistakes. While this is not a pain-free approach, you should be able find a lot of bugs in a very short amount of time.

Basics

All the test fixtures inherit from a single base class: ApiBaseTest.cs. It defines an Assembly property that you’ll need to override to point to your binding assembly. E.g. to test the Cocos2D bindings you would need this piece of code:

protected override Assembly Assembly {
     get { return typeof (CCAccelAmplitude).Assembly; }
}

This base fixture also allow us to cheat a bit by introducing two properties that you should, when you start testing, set to true in your own inherited fixtures. Once every failure has been fixed it’s safe to turn them off—and let the test fixtures behave like any others.

ContinueOnFailure = true;

This property will avoid stopping the test execution when failing an assertion. Doing otherwise would require too many “build / run / debug” cycles to go through dozens (or thousands) of types, methods or parameters. You’ll often be able to fix several issues between builds, progressing a lot quicker toward your goal.

LogProgress = true;

It’s likely you’ll hit bugs that will crash your testing process—for example, a bad API signature can corrupt the stack. When that occurs, you want to know what was being executed. Turning on the LogProgress property will give you this information (and a lot of lines in your console).

Even with those properties to help you, there will be failures that require a bit more knowledges to solve—ways to ignore (special cases) or when the test fixture requires a bit of extra help to get the most of out them. To help you get down to zero failures, each test fixture will be documented in it’s own blog entry. Stay tuned for the rest of the series!

Read the rest of the series:

Discuss this post in the Xamarin Forums

Feedback usabilla icon