Runar Ovesen Hjerpbakk

Science-based software development

NDC 2013, Day 3

Aka. the day of automated testing.

Sharing C# across Windows, Android and iOS using MvvmCross

MvvmCross is an excellent framework for data binding ++ on Xamarin's supported platforms. Stuart Lodge gave a talk explaining the motivation, history, philosophy and current state of the framework.

MvvmCross makes it easy to implement the MVVM-pattern on iOS, Android, Windows Phone, Mac, Win RT and others, and facilitates code sharing of the ViewModel logic across all the supported platforms. With the help of PCL (Portable Class Libraries), you can achieve code sharing in the upper 80%s of your code base. Even more if you use little custom UI. The view itself cannot be shared, and that is as it should be.

MvvmCross solution structure

Properly decoupled view models are easy to test and with the code shared across all your platforms, the tests will have high value.

MvvmCross enables cross platform development with native UI and performance, together with easily testable code. I've used MvvmCross myself and highly recommend it to everybody interested in multi-platform development. For an introduction, check out the MvvmCross N+1 video series.

Full session on Vimeo.

Succeeding with TDD: Pragmatic Techniques for effective mocking

Venkat Subramaniam gave an introduction to mocking in C# and helpful pointers when working with test-driven development (TDD).

[TestClass]
public class MockExample
{
    /// <summary>
    /// An interface for an imaginary stock service.
    /// </summary>
    public interface IStockService
    {
        double QuoteForTicker(string ticker);
    }

    /// <summary>
    /// Class representing an application model.
    /// Utilizes the IStockService in its implementation.
    /// </summary>
    public class SampleApplicationModel
    {
        private readonly IStockService stockService;

        public SampleApplicationModel(IStockService stockService)
        {
            this.stockService = stockService;
        }

        public string CurrentTicker { get; set; }
        public string LatestQuote { get; set; }

        public void GetQuote()
        {
            var quote = stockService.QuoteForTicker(CurrentTicker);
            LatestQuote = quote.ToString();
        }
    }
   
    [TestMethod]
    public void GetQuoteMustSetLatestQuoteForTicker()
    {
        // Simple mock, using an appropriate tool
        var stockServiceFake = new Mock<IStockService>();
        stockServiceFake.Setup(s => s.QuoteForTicker("AAPL")).Returns(700D);
        var model = new SampleApplicationModel(stockServiceFake.Object) { CurrentTicker = "AAPL" };

        // Mock with internal logic
        //var model = new SampleApplicationModel(new StockServiceFake()) { CurrentTicker = "AAPL" };

        model.GetQuote();

        Assert.AreEqual("700", model.LatestQuote);
    }

    [TestMethod]
    [ExpectedException(typeof(InvalidOperationException))]
    public void GetQuoteLFailsMustSetErrorMessageAsQuoteValue()
    {
        // Simple mock, using an appropriate tool
        var stockServiceFake = new Mock<IStockService>();
        stockServiceFake.Setup(s => s.QuoteForTicker("AAPL")).Throws(new InvalidOperationException());
        var model = new SampleApplicationModel(stockServiceFake.Object) { CurrentTicker = "AAPL" };

        // Mock with internal logic
        //var model = new SampleApplicationModel(new StockServiceFake(true)) { CurrentTicker = "AAPL" };

        model.GetQuote();
    }

    /// <summary>
    /// Complicated mock. Hard to understand, must be maintained
    /// together with the interface it's implementing.
    /// </summary>
    private class StockServiceFake : IStockService
    {
        private readonly bool throwException;

        public StockServiceFake(bool throwException = false)
        {
            this.throwException = throwException;
        }

        public double QuoteForTicker(string ticker)
        {
            if (throwException) 
            {
                throw new InvalidOperationException();
            }

            return 700D;
        }
    }
}

I would have stressed more that you don't start with TDD, you start with unit tests. Understanding how to write relevant and well designed tests are a precursor for a successful application of TDD.

Full session on Vimeo.

C# 5

Jon Skeet, best known from Stack Overflow and as an author of the books C# in Depth, talked about async await in C# 5.

His focus was somewhat different from Venkat's previous talk. Rather than starting with C# threading basics, Jon made the case for async and await using metaphors and code examples. As we've previously learned, asynchrony does not equal parallelism.

C# in its current iteration has many different APIs for dealing with asynchrony. Your code will be easier to develop, understand and extend if you stick with one of these paradigms. Switching points between synchronous and asynchronous code can be painful.

Jon stressed the need for giving the user early feedback. For example, show items in a list as they come in. Don't wait for all the items before giving the user the option to work with the data. Also, validate input as early as possible so that exceptions caused by bad input do not happing during the asynchronous operations.

Testing was the last topic:

C# 5 lets you focus on the difficult bits... And that's good!

Full session on Vimeo.