Introducing Suave Streams

Welcome to Suave Streams at https://twitch.tv/suave_pirate where I’ll be taking some time twice a week to build some of the coolest, funniest, and also innovative pieces of software using real-world patterns, practices, and tools.

Come for a laugh, come to build, and come to learn! We’ll be jumping into languages, and tools like:

  • C#
  • TypeScript
  • Kotlin
  • Swift
  • ASP.NET Core
  • Alexa Skills
  • Actions on Google
  • Bixby Capsules
  • Conversational AI
  • Real time communications
  • Xamarin/Maui.NET
  • UWP
  • Game Development
  • Bot building

and so much more!

We’re starting off with a schedule of every:

  • Sunday 12:30-4:30PM EST
  • Wednesday 6-10PM EST

I hope you’ll join for our first ever livestream this Sunday, May 22nd at 12:30pm EST where we are starting to build an Alexa Skill to Beat Call of Duty Warzone! Using:

C#, ASP.NET Core APIs, SignalR, UWP, Alexa Skills SDK, and scalable architectures and design patterns to make it come to life.

After each stream, I’ll also be uploading the whole recording (with minor edits) to my YouTube over at https://www.youtube.com/channel/UC1ycVqsWOInQuel68295M7w

So if you can’t make the stream, you won’t miss out on all the fun. Be sure to follow me on twitch for updates on when I go live and to keep up with the projects we start creating!

See you there!

 

 

Xamarin.Tip – iOS Push Notification Device Token Extraction in iOS 13+

This weekend, I spent some time getting some apps updated with the latest Xamarin, iOS, Android, etc. A lot of these apps make use of push notifications across platforms. I was running some automated tests against them to do the following steps:

  • Register for push notifications on sign-in / startup
  • Send registration update details to API
  • API sends updates to Azure Notification Hub or Firebase (depends on the project)
  • Send push notification to all test users
  • Send push notification to specific test user

I noticed immediately that all my new iOS builds were failing to receive any push notifications after updating registrations.

Time to debug!

The Old Way

Here was my original method for kicking off the push notification registration:

AppDelegate.cs

//...
private void RegisterForPush()
{
    if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
    {
        UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
            (granted, error) =>
            {
                if (granted)
                    InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
            });
    }
    else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
    {
        var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
                new NSSet());

        UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
        UIApplication.SharedApplication.RegisterForRemoteNotifications();
    }
    else
    {
        UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
        UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
    }
}
// ..

This processes kicks off the internal iOS process to start registration. It will check against your apps registered entitlements for push, check the environment it should be using between development and production, and then if all goes well, it will hit the RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) method in the AppDelegate. If there are any explicit errors it will instead hit FailedToRegisterForRemoteNotifications(UIApplication application, NSError error).

So what we need is the data within that deviceToken of the RegisteredForRemoteNotifications method to send to our API.

Here is what the ORIGINAL implementation looked like (with some of the abstractions removed for simplicity):

AppDelegate.cs

// non-user registration
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    // if using default registration with notification hub for non-user apps
    Hub = new SBNotificationHub("{CONN_STRING}", "{AZURE_HUB_NAME}");

    Hub.UnregisterAll(deviceToken, (error) =>
    {
        if (error != null)
        {
            System.Diagnostics.Debug.WriteLine("Error calling Unregister: {0}", error.ToString());
            return;
        }

        NSSet tags = null; // create tags if you want
        Hub.RegisterNativeAsync(deviceToken, tags);

    });
}

And for handling specific user registration, we need to send it to the API:

AppDelegate.cs

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var token = deviceToken?.Description?.Trim('<', '>')?.Replace(" ", string.Empty);
    if (!string.IsNullOrEmpty(token))
    {
        // this sends the handle to the API to do all the registration
        var remoteRegistrar = new RemoteNotificationRegistrar();
        remoteRegistrar.RegisterForPushAsync("apns", token);
    }
}

Debugging showed me the issue was here:

var token = deviceToken?.Description?.Trim('<', '>')?.Replace(" ", string.Empty);

The token was no longer in the same format… Feeling like an idiot who has been out of the loop, I hit the internet to see what I missed and landed on some of these lovely articles and posts:

So lets do this update in Xamarin:

The New Way

So the old token structure looked like this:

And the new token looks like this:

{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }

So basically we need a clean version of that bytes property of the NSData object.

Azure notification hubs already do this behind the scenes, but we need the clean version for our own method to send to our API, so here’s the new version:

AppDelegate.cs

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var token = ExtractToken(deviceToken);
    if (!string.IsNullOrEmpty(token))
    {
        // this sends the handle to the API to do all the registration
        var remoteRegistrar = new RemoteNotificationRegistrar();
        remoteRegistrar.RegisterForPushAsync("apns", token);
    }
}

private string ExtractToken(NSData deviceToken)
{
    if (deviceToken.Length == 0)
        return null;
    var result = new byte[deviceToken.Length];
    System.Runtime.InteropServices.Marshal.Copy(deviceToken.Bytes, result, 0, (int)deviceToken.Length);
    return BitConverter.ToString(result).Replace("-", "");
}

There are a few different ways to write this ExtractToken method, but this is what has worked for me!.

After making this change and running it on iOS 13, I started getting user notifications again!

Both Ways

This is great and all, but I still want to make sure folks who haven’t updated to iOS 13 can still use my apps, so I added some explicit version checks to decide which way to extract the token. Here’s what the final looks like all within that ExtractToken method:

private string ExtractToken(NSData deviceToken)
{
    if(UIDevice.CurrentDevice.CheckSystemVersion(13,0))
    {
        if(deviceToken.Length > 0)
        {
            var result = new byte[deviceToken.Length];
            Marshal.Copy(deviceToken.Bytes, result, 0, (int)deviceToken.Length);
            return BitConverter.ToString(result).Replace("-", string.Empty);
        }
    }
    else 
    {
        return deviceToken?.Description?.Trim('<', '>')?.Replace(" ", string.Empty);
    }

    return null;
}

And that’s it! Try this out if you’re having issues with the latest iOS 13 update and your push notification registration.

If you’re still having problems with push notification registration in general, leave a comment below! I’d love to put together an article about the common pitfalls of push notifications on both iOS and Android with a checklist of things to look at, fix, or build on top of what you have!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile and AI developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.


CodeMash 2020 This Week!

This week I’ll be at CodeMash – an amazing developer event at the Kalahari Resort in Ohio. CodeMash holds a special place in my heart; It’s the first developer conference I ever attended, the first I ever sponsored, and now I have the honor of being a speaker!

This year, I’ll be talking more about Kotlin for C# developers, and you can catch the session at 9:15 am on Thursday.

Annotation 2020-01-06 113339

If you’re looking to expand your language portfolio with something familiar yet new as a C# developer, you’re going to love this session. Learn about the Kotlin programming language side-by-side with C#, compare and contrast both languages’ amazing features and tooling and walk away with the confidence to to explore and build more with both languages and stacks.

Check out the schedule and other speakers here: https://www.codemash.org/

If you’re at the conference or the area, let me know! I’d love to chat.


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Fixing Missing iOS App Icons

In the age of Xamarin Hot Reload and Hot Restart, we are beginning to get spoiled with the tooling we use every day. I find myself spending less and less time dealing with workarounds for Xamarin issues, filing bug reports, or getting frustrated at not understanding why something isn’t working.

Until today…

The issue – I created an AppIcon for my iOS app, and it simply won’t show up on any device or simulator. I had seen this before, so I double checked everything and tried all my old tricks:

  • Check that the AppIcon asset was in the Assets.xcassets
  • Check that the actual AppIcon had all the images filled in
  • Check that my info.plist was pointing at my AppIcon
  • Clean
  • Rebuild
  • Clear all caches
  • Restart VS
  • Restart machine
  • Try on another machine, repeat above steps
  • Panic

Nothing. So, if you’re new to Xamarin development or iOS development in general, the above steps are definitely the first things to try!

One thing I did differently this time around was use https://makeappicon.com/ to generate my individual icons from a single high resolution image. Usually the designer on my team will send me the exact icons exported to the specific sizes, but they were on vacation and I wanted to make some progress! I 100% recommend using MakeAppIcon for those who haven’t discovered it yet.
For those that haven’t used it, MakeAppIcon gives you a zip with the actual AppIcon.appiconset which includes every size you need and their registration in the Contents.json which tells the build agent what images fit which profile/size. This Contents.json is also what Visual Studio uses to show you the icons in your Assets.xcassets.

So all you have to do is take the AppIcon.appiconset and drop it in your Assets.xcassets and you’re off and running. Or so I thought…

Turns out VS uses the Content.json to read the images to show in your assets, but this does not actually include them in any sort of build output to your final .ipa – so we need to actually update our ios project’s .csproj file to make sure all the images and their full paths are included – not just the AppIcon.appiconset. Normally, if you drag and drop or file select within Visual Studio to set the images for your app icon, this is done for you. But if you bring in your icons from any outside source, be sure to make sure you add them in the .csproj – something like this:

<ImageAsset Include="Assets.xcassets\AppIcons.appiconset\Contents.json">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Contents.json">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-60x60@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-60x60@3x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-76x76@1x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-76x76@2x.png">
  <Visible>false</Visible>
</ImageAsset>
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-App-83.5x83.5@2x.png">
  <Visible>false</Visible>
</ImageAsset>

Long story short – copy paste this into your .csproj if you use MakeAppIcon and save yourself some time. If this didn’t help you or isn’t why your App icon isn’t showing up, here are some links I’ve used in the past:
https://stackoverflow.com/questions/48375681/ios-app-icon-missing-on-ios-11
https://xamarin.github.io/bugzilla-archives/59/59515/bug.html
https://docs.microsoft.com/en-us/xamarin/ios/app-fundamentals/images-icons/app-store-icon
https://blog.rthand.com/post/2017/10/17/app-icons-missing-after-upgrading-to-ios-11-xamarin.aspx


More meaningful and useful content coming soon! Including more Alexa, Dialogflow, Google Assistant, Bixby, Cortana, and of course Xamarin work 🙂


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Techorama This Week – Kotlin, C#, Flux, Design Patterns, and more!

If you’re in the Netherlands this week, come catch me at Techorama! I’ll be there from the 30th through the 3rd of October and presenting two different sessions:

techorama_sessions

On the 1st, I’ll be speaking on Kotlin for C# Developers:

Dive into the latest craze in languages and platforms – Kotlin. This time we will be looking at it from the perspective of a .NET C# developer, draw comparisons between the languages, and bridge the gap between these 2 amazing languages. We’ll look at: – Kotlin as a language – Platforms Kotlin is great for – Object Oriented Implementations in Kotlin – Extended Features – Features Kotlin has that C# doesn’t – A demo Android application in Kotlin vs a Xamarin.Android app in C# In the end you will leave with a foundational knowledge of Kotlin and its capabilities to build awesome apps with less code. You should feel comfortable comparing C# applications to Kotlin applications and know where to find resources to learn even more!
And on the 2nd I have another morning session on implementing the Flux design pattern in C# and .NET:
Learn about the Flux design pattern and how to implement it in your C# client applications like UWP, Xamarin, and all the other platforms .NET is touching now. We’ll compare Flux and Uni-Directional data flows to the existing tools and directions development takes us in C# client apps and talk about all the pros and cons that come with both. We’ll take an existing Xamarin.Forms app using MVVM and “Flux it Up” to migrate to a more 1-direction flow of data and actions. When you leave, you’ll have a solid understanding of Flux and some of its existing implementations such as Redux and be confident in implementing it yourself in C#!

Pre-conference Meetup

If you’re not going to Techorama this year, but are still in the area, you can find me tomorrow at the Dutch Mobile .NET Developers meetup with some of the other amazing people from the Xamarin and .NET Community. I’ll be on a panel talking about mobile technologies and practices!

2019 Meetup – Xamarin with David Ortinau & Mobile Expert Panel

Monday, Sep 30, 2019, 6:00 PM

Info Support
Kruisboog 42 Veenendaal, NL

50 Code monkeys Attending

18:00 Doors open & Dinner 19:00 – 20:00 *The Latest and Craziest for Mobile .NET Developers* David Ortinau @davidortinau Microsoft has been hard at work improving Visual Studio and Xamarin for mobile developers. I’ll demo the latest features you can use to make your dev experience better today. And in the future? Microsoft has some “coming soon” as…

Check out this Meetup →

 

Here’s the schedule:

18:00 Doors open & Dinner
19:00 – 20:00 The Latest and Craziest for Mobile .NET Developers
David Ortinau @davidortinau
Microsoft has been hard at work improving Visual Studio and Xamarin for mobile developers. I’ll demo the latest features you can use to make your dev experience better today. And in the future? Microsoft has some “coming soon” as well as highly experimental projects that are “must see”!

20:00 – 20:15 Break
20:15 – 21:00 Mobile Expert Panel with Alex, Brandon, Dan & Gerald
Open Q&A for these mobile experts that have absolutely made their mark in the mobile developer space. This is your chance to ask anything you’d like! Joining us are:

Alex Dunn @suave_pirate
Author at Pluralsight | Xamarin MVP | Microsoft MVP

Brandon Minnick @thecodetraveler
Microsoft Developer Advocate | Mobile App Developer

Dan Siegel @danjsiegel
Microsoft MVP | @PrismLib Maintainer | Xamarin Evangelist | @XamDevSummit Organizer

Gerald Versluis @jfversluis
Engineer @Microsoft for #XamarinForms | Former Microsoft MVP

21:00 Drinks & Closing

 

See ya’ll there!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

HACKMIT 2019 This Weekend!

HackMIT is this weekend, September 14-15th.

I’m happy to announce that I’ll be mentoring as one of the local Microsoft MVPs that were invited to help as part of the Microsoft sponsorship of the event. I look forward to building some incredible applications with some of the brightest students coming to Cambridge! Hack for a reason 🙂

Check out some of the awesome tracks:

hackmit_tracks

 

If you’re hacking this weekend, come find me for help with:

  • Conversational AI
  • Voice First Development
  • Azure
  • AWS
  • Machine Learning
  • Unity
  • C#
  • JavaScript/TypeScript
  • Kotlin
  • React
  • Video Editing
  • and RTC

See ya’ll there!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Alexa.Tip – Build Unit Tested Skills in .NET

In this Alexa.Tip series, we explore some little bits of code that can make your life easier in developing Alexa Skills in many languages including C# + .NET, node.jS + TypeScript, Kotlin, etc. We look at concepts, design patterns, and implementations that developers might not be aware of, and how they can be applied to voice application development, best practices, and more!

In this post, we explore some more best practices in developing Alexa Skills in C# whether you are using an ASP.NET Core API or an AWS Lambda. This post will expand our previous posts about building better abstractions for handling Alexa responses and demonstrate how we can now properly Unit test these handlers as well as any other separated bits of logic that the Handler implementations consume.

Check out all the raw source code for this post, and more here: https://github.com/SuavePirate/Alexa.Tips.Net

Prerequisite

If you haven’t read up on how to use the Handler Registration Pattern, take a look at my earlier post here: Alexa.Tip – Using Handler Registration Pattern in .NET

The short version is that we use this pattern of registering IHandler implementations to handle different types of requests that our skill receives, regardless of whether we are using AWS Lambdas or ASP.NET Core APIs.

Unit Testing Handlers

Since we now have nice atomized units (Handlers) built for each of our RequestTypes and Intents, they are SCREAMING to be unit tested. So, we can easily test them against different scenarios given our positive and negative cases.

Take for example, the SimpleLaunchHandler that is responsible only for LaunchRequest, and whose HandleAsync() implementation returns a static response. The two main cases we want to test against is the HandleAsync() returning properly for a proper LaunchRequest, and that the CanHandle() implementation returns false for non LaunchRequest skill requests.

In these samples, I’m using xUnit for my Unit tests, but the same concept is applicable with any other Unit testing framework (and really any other language).

In each case, we want to separate our 3 A’s of testing, “Arrange”, “Act”, and “Assert”. For these basic examples, the three steps are pretty clear.

  1. Arrange the Testable SkillRequest object
  2. Act on the subject’s method we are testing by sending it the SkillRequest
  3. Assert our final response

Let’s first test the CanHandle() against the postive case, meaning we want to send it data we want to be successful:

public class SimpleLaunchHandlerTests
{
    private readonly SimpleLaunchHandler _subject;
    public SimpleLaunchHandlerTests()
    {
        _subject = new SimpleLaunchHandler();
    }


    [Fact]
    public void SimpleHandler_CanHandleLaunchRequest()
    {
        // arrange
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new LaunchRequest
            {
                Type = "LaunchRequest"
            }
        };

        // act
        var canHandle = _subject.CanHandle(request);

        // assert
        Assert.True(canHandle);
    }

}

Now let’s perform the opposite by sending it a request of a different type:

 [Fact]
public void SimpleHandler_CanNotHandleIntentRequest()
{
    // arrange
    var request = new SkillRequest()
    {
        Version = "1.0",
        Request = new IntentRequest
        {
            Type = "IntentRequest"
        }
    };

    // act
    var canHandle = _subject.CanHandle(request);

    // assert
    Assert.False(canHandle);
}

Now, we can look at the positive example of passing the LaunchRequest into the HandleAsync method:

[Fact]
public async Task SimpleHandler_ReturnsResponse()
{
    // arrange
    var request = new SkillRequest()
    {
        Version = "1.0",
        Request = new LaunchRequest
        {
            Type = "LaunchRequest"
        }
    };

    // act
    var response = await _subject.HandleAsync(request);

    // assert
    Assert.NotNull((response.Response.OutputSpeech as PlainTextOutputSpeech)?.Text);
}

Now that we have our LaunchRequest tested, let’s take a look at a simple static IntentRequest set of tests:

DogFactHandlerTests.cs

public class DogFactHandlerTests : IClassFixture<DogFactHandler>
{
    private readonly DogFactHandler _subject = new DogFactHandler();


    [Fact]
    public async Task DogFactHandler_ReturnsResponse()
    {
        // arrange
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "DogFactIntent"
                }
            }
        };

        // act
        var response = await _subject.HandleAsync(request);

        // assert
        Assert.NotNull((response.Response.OutputSpeech as PlainTextOutputSpeech)?.Text);
    }

    [Fact]
    public void DogFactHandler_CanHandleIntentRequest()
    {
        // arrange
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "DogFactIntent"
                }
            }
        };
        // act
        var canHandle = _subject.CanHandle(request);

        // assert
        Assert.True(canHandle);
    }
    [Fact]
    public void DogFactHandler_CanNotHandleLaunchRequest()
    {
        // arrange
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new LaunchRequest
            {
                Type = "LaunchRequest"
            }
        };


        // act
        var canHandle = _subject.CanHandle(request);

        // assert
        Assert.False(canHandle);
    }
    [Fact]
    public void DogFactHandler_CanNotHandleOtherIntents()
    {
        // arrange
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "AMAZON.HelpIntent"
                }
            }
        };


        // act
        var canHandle = _subject.CanHandle(request);

        // assert
        Assert.False(canHandle);
    }
}

Okay, cool, but what about stuff that isn’t static? What if I’m getting my data from somewhere else and want to test those cases? Let’s bring Moq into the picture!

Let’s take this handler for example:

SampleFactHandler.cs

public class SampleFactHandler : GenericHandler, IHandler
{
    private readonly SampleMessageDbContext _context;
    public SampleFactHandler(SampleMessageDbContext context)
    {
        _context = context;
    }
    public override string IntentName => "SampleMessageIntent";

    public override Type RequestType => typeof(IntentRequest);

    public override async Task<SkillResponse> HandleAsync(SkillRequest request)
    {
        // just grab one as an example
        var message = await _context.SampleMessages.FirstOrDefaultAsync();
        return ResponseBuilder.Tell(message?.Content ?? "I don't have any messages for you.");
    }
}

So this Handler uses an Entity Framework Core DbContext with a table of SampleMessage objects to get the content. In this sample, we just grab the first one, but you could imagine some more complex data-logic to pull out the proper message.

To unit test this, we can pass in different “Mock” implementations of the SampleMessageDbContext. For this, I usually use Moq, but you can also pass in a full implementation that you’ve built yourself.

Here are some samples of testing this with different Moq’d contexts to test a few scenarios. Note: we still want to test against the CanHandle and HandleAsync as well, but now we have two different cases to test for such as if there are no messages in the db, and when there is one.

SampleFactHandlerTests.cs

public class SampleFactHandlerTests
{
    [Fact]
    public async Task SampleFactHandler_ReturnResponseWithData()
    {
        // arrange
        var context = new Mock<SampleMessageDbContext>();
        context.Setup(d => d.SampleMessages.FirstOrDefaultAsync(CancellationToken.None)).Returns(Task.FromResult(new SampleMessage
        {
            Id = Guid.NewGuid().ToString(),
            Content = "This is a mocked response message"
        }));
        var subject = new SampleFactHandler(context.Object);
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "SampleMessageIntent"
                }
            }
        };

        // act
        var response = await subject.HandleAsync(request);

        // assert
        Assert.NotNull((response.Response.OutputSpeech as PlainTextOutputSpeech)?.Text);
    }
    [Fact]
    public async Task SampleFactHandler_ReturnFallbackResponseWithNoData()
    {
        // arrange
        var context = new Mock<SampleMessageDbContext>();
        context.Setup(d => d.SampleMessages.FirstOrDefaultAsync(CancellationToken.None)).Returns(Task.FromResult<SampleMessage>(null));
        var subject = new SampleFactHandler(context.Object);
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "SampleMessageIntent"
                }
            }
        };

        // act
        var response = await subject.HandleAsync(request);

        // assert
        Assert.True((response.Response.OutputSpeech as PlainTextOutputSpeech)?.Text == "I don't have any messages for you.");
    }
}

We can also, and probably should also add some CanHandle and non-assinable Intent types to test, but for the sake of not making you read the same thing over and over again, these are the two that matters.

Unit Testing Controllers

Personally, I don’t typically unit test my Controllers, but that’s because I have some general rules in place to not change them one they are implemented. However, when working on a team, it may be easier and more sustainable to implement a few test on the controller to guarantee that changes made to it don’t affect the currently working implementation.

Some basic positive/negative test might look like this:

SimpleAlexaControllerTests.cs

public class SimpleAlexaControllerTests
{
    [Fact]
    public async Task AlexaController_ResponseWithHandler() 
    {
        // arrange
        var subject = new SimpleAlexaController(new List<IHandler>{ new DogFactHandler() });
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "DogFactIntent"
                }
            }
        };
        // act
        var response = _subject.HandleRequest(request);

        // assert
        Assert.NotNull((response.Response.OutputSpeech as PlainTextOutputSpeech)?.Text);
    }

    [Fact]
    public async Task AlexaController_ResponseWithoutHandler() 
    {
        // arrange
        var subject = new SimpleAlexaController(new List<IHandler>{ new SimpleLaunchHandler() }); // no DogFactHandler
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "DogFactIntent"
                }
            }
        };

        // act
        var response = _subject.HandleRequest(request);

        // assert
        Assert.Null(response);
    }
}

Unit Testing Lambda Functions

Just like testing the Controller, if you are using AWS Lambda rather than ASP.NET Core, you can create unit tests against your Function endpoint in order to get some coverage. That could look simple like something here:

FunctionHandlerTests.cs

public class FunctionHandlerTests
{

    [Fact]
    public async Task LambdaFunction_ResponseWithHandler() 
    {
        // arrange
        var subject = new SimpleAlexaHandler();
        subject.Handlers = new List<IHandler>{ new DogFactIntent() });
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "DogFactIntent"
                }
            }
        };
        // act
        var response = _subject.HandleRequest(request, null);

        // assert
        Assert.NotNull((response.Response.OutputSpeech as PlainTextOutputSpeech)?.Text);
    }

    [Fact]
    public async Task LambdaFunction_ResponseWithoutHandler() 
    {
        // arrange
        var subject = new SimpleAlexaHandler();
        subject.Handlers = new List<IHandler>{ new SimpleLaunchHandler() }); // no DogFactIntent handler
        var request = new SkillRequest()
        {
            Version = "1.0",
            Request = new IntentRequest
            {
                Type = "IntentRequest",
                Intent = new Intent
                {
                    Name = "DogFactIntent"
                }
            }
        };

        // act
        var response = _subject.HandleRequest(request);

        // assert
        Assert.Null(response);
    }

}

That’s all the unit test types for now! Anything else that needs testing would be tested outside the Alexa specific logic. But hey! Now we can write some strong and code-covered tested skills which leads to better skills overall

What’s next?

Check out more Alexa Developer Tips here: https://alexdunn.org/tag/alexa/


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile and AI developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.


voicify_logo
I’m the Director and Principal Architect over at Voicify. Learn how you can use the Voice Experience Platform to bring your brand into the world of voice on Alexa, Google Assistant, Cortana, chat bots, and more: https://voicify.com/