Unit testing ArcGIS Runtime SDK for .NET

6507
12
02-11-2015 05:24 AM
JuhoVainio
Occasional Contributor

As far as I know, the current ArcGIS Runtime SDK for .NET cannot be unit tested because we simply cannot create new instances from the classes and thus cannot mock any return values from queries. The older ArcObjects library was easier to mock, because every class also had an interface assigned to it.

Currently this is a bit of a problem because we cannot create unit tests for ANY functionality that uses any of the ESRI's classes (or they become integration tests).

Is ESRI going to upgrade the SDK so that unit testing might be possible in the near future?

Tags (2)
0 Kudos
12 Replies
dotMorten_esri
Esri Notable Contributor

Most of the API can be unit tested (we have thousands of unit tests ourselves). You are correct that some classes - mainly data coming from the server are not creatable or settable - the API is strict on mimicking the nature on the server (ie some things just aren't settable) and we'd like to keep it that way. We did have a prototype early on to mock server responses, so that you can mock results but had to be pulled out. We do want to revisit that in the near future (note: this isn't mocking classes but mocking the server). You could accomplish this with a proxy though.

We don't want to get into the interface hell that COM has forced onto ArcObjects. For example we don't want to find ourselves with 7 polyline interfaces in the future. It's just not a pretty API to work with in the long run.

0 Kudos
JuhoVainio
Occasional Contributor

Thanks for the quick reply. It would be great if you could share an example solution that would contain some example unit tests. What testing framework are you using by the way? We're using Moq.

Also about mocking server response: currently it's quite impossible to unit test our data access layer, because for example FeatureTable's constructor is internal. So I'm hoping you'd come up with some improvements on that later.

And you're absollutely correct about the interface hell, it wasn't very convenient

0 Kudos
dotMorten_esri
Esri Notable Contributor

We are using Visual Studio's unit test framework and nUnit.

Wrt to FeatureTable - it is an abstract class and subclasses are implemented at the native level and therefore we can't support subclassing this directly. This actually goes for quite a lot of the classes, and why you see a lot of sealed or non-creatable classes. Other cases, it's to properly convey that data isn't editable and is kept read-only.

0 Kudos
JuhoVainio
Occasional Contributor

Thanks for taking the time to answer. I hope you can improve the SDK's unit testing capabilities in the future.

0 Kudos
dotMorten_esri
Esri Notable Contributor

Just a thought: Have you considering using duck typing to achieve this? Here's a good article discussing it with an example further down that matches exactly you scenario (and gives you the interfaces you asked for): http://haacked.com/archive/2007/08/19/why-duck-typing-matters-to-c-developers.aspx/

FridjofSchmidt
Occasional Contributor

Although the DuckTyping approach looks interesting, it still leaves it to the developer to hand-write all the interfaces. Moreover, when doing so, any typo will compile and lead to exceptions at runtime. I fully agree with Juho that unit testing of applications based on the Runtime SDK for .NET is currently very cumbersome. It is obvious that design goals for testability didn't play a part when the Runtime SDK was developed. The result is a lack of seams where original classes can be replaced with stubs: The SDK does not define interfaces, and most of the classes are sealed and/or have non-public constructors. If at least classes were not sealed, it would be possible to create stubs for them with common isolation or mocking frameworks such as Moq, FakeItEasy or NSubstitute.

I also would like to see a sample project of unit tests for the API. How do you isolate the class under test from its dependencies? How do you create stubs for parameters that you pass to the tested method, if that parameter is of a sealed type with no public constructor?

dotMorten_esri
Esri Notable Contributor

That is fair feedback, but we did think of this - However another very big design goal was to reduce the API surface to simplify using it, and also reduce the number of checks needed to improve performance. It's for instance misleading to have an interface you can implement but not pass to any other object (we wouldn't be able to support this because everything is really implemented at the C++ level). And we don't want created interfaces that aren't used - nor get into the interface-hell COM got ArcObjects into. Lastly we want the API to be clear on what you can set and what you can't. Setting a property on a server object doesn't mean the server changes - and at the same time it saves a lot of checked for whether someone set a property that could pull the rug out under the SDK.

Unfortunately we had to pull the server mocking functionality, which is the main thing that returns objects you can't mock. We are working on bringing this back, but it would solve this scenario and help you perform tests.

Wrt to sharing API tests: You shouldn't have to worry about testing our API - that's our job

FridjofSchmidt
Occasional Contributor

Well, I don't worry about testing your API (and I'm glad that you do this), but I worry about all the developers who want to write testable code with your SDK. Therefore I was hoping for some examples and recommendations. The server mocking functionality would be a start for sure, and I hope you can bring it back soon for the TDD guys out there.

MarkoApfel
New Contributor

In such cases sometimes the commercial Typemock mocking framework brings you a step further. It allows a more sophisticated approach of mocking and faking. In minimum it is worth to have a look onto the 15 days trial version, whether it satisfies your wishes or not. I used it a while ago in another context and was absolutely surprised what that framework allows.

0 Kudos