Saturday, September 20, 2014
Refactor vs rewrite (again)
Friday, August 22, 2014
Azure DocumentDB First Look
Step 1: Run the PowerShell Scripts
Step 2: Use the new Azure portal at portal.azure.com
Step 3: Run NuGet: Install-Package Microsoft.Azure.Documents.Client -Pre
Step 4: This is the Flashcard class
public class FlashCard { [JsonProperty(PropertyName = "id")] public string ID { get; set; } [JsonProperty(PropertyName = "question")] public string Question { get; set; } [JsonProperty(PropertyName = "answer")] public string Answer { get; set; } }Step 5: This is the console application:
internal class Program { private static void Main(string[] args) { CreateSaveAndGet().Wait(); //CleanUp().Wait(); } public static async Task CreateSaveAndGet() { //connect database var client = GetClient(); //find or create a database var database = await GetDatabase(client); //create a collection var collection = await GetCollection(client, database); Console.WriteLine("Save new flashcards..."); var flashcard1 = await client.CreateDocumentAsync(collection.SelfLink, new FlashCard() { ID = "1", Question = "When did Azure DocumentDB release in preview?", Answer = "August 21st, 2014", }); var flashcard2 = await client.CreateDocumentAsync(collection.SelfLink, new FlashCard() { ID = "2", Question = "What is Azure DocumentDBs twitter handle?", Answer = "@DocumentDB", }); var flashcards = await Task.Run(() => client.CreateDocumentQuery(collection.DocumentsLink) .AsEnumerable() .ToList()); Console.WriteLine("Iterating through flashcards..."); foreach (var flashcard in flashcards) { Console.WriteLine("QUESTION " + flashcard.ID.ToString() + ": " + flashcard.Question); Console.WriteLine("Answer: " + flashcard.Answer); Console.WriteLine("Press a key"); Console.ReadKey(); } Console.ReadKey(); var flashcardGet = await Task .Run(() => client.CreateDocumentQuery (collection.DocumentsLink) .Where(d => d.ID == "1") .AsEnumerable() .FirstOrDefault()); Console.WriteLine(flashcardGet.Question); Console.ReadKey(); var doc = client.CreateDocumentQuery (collection.DocumentsLink) .Where(d => d.Id == flashcardGet.ID) .AsEnumerable().FirstOrDefault(); await client.DeleteDocumentAsync(doc.SelfLink); flashcardGet = await Task .Run(() => client.CreateDocumentQuery (collection.DocumentsLink) .Where(d => d.ID == "1") .AsEnumerable() .FirstOrDefault()); Console.WriteLine(flashcardGet.Question); Console.ReadKey(); } private static async Task CleanUp() { //connect database var client = GetClient(); //find or create a database var database = await GetDatabase(client); //create a collection var collection = await GetCollection(client, database); await client.DeleteDocumentCollectionAsync(collection.SelfLink); } private static DocumentClient GetClient() { string endpoint = ConfigurationManager.AppSettings["EndPoint"]; string authKey = ConfigurationManager.AppSettings["AuthKey"]; Uri endpointUri = new Uri(endpoint); var client = new DocumentClient(endpointUri, authKey); return client; } private static async Task GetDatabase(DocumentClient client) { Database database; var databaseName = "flashcards"; var databases = client.CreateDatabaseQuery() .Where(db => db.Id == databaseName).ToArray(); if (databases.Any()) { database = databases.First(); } else { database = new Database { Id = databaseName }; database = await client.CreateDatabaseAsync(database); } return database; } private static async Task GetCollection(DocumentClient client, Database database) { var collectionName = "flashcards"; DocumentCollection collection; var collections = client.CreateDocumentCollectionQuery(database.SelfLink) .Where(col => col.Id == collectionName).ToArray(); if (collections.Any()) { collection = collections.First(); } else { collection = await client.CreateDocumentCollectionAsync(database.SelfLink, new DocumentCollection { Id = collectionName }); } return collection; } }
Saturday, August 2, 2014
Simplifying Andoid Concepts
When it comes to Android there are fundamental concepts that a programmer *must* understand in order to author code for the platform or to understand code found online. You need to understand these concepts even if you are writing the application in Xamarin or some other abstraction layer.
From the Android developer web pages (http://developer.android.com/) you can find out that by default, every app runs in its own Linux process. Components are the essential building blocks of an Android app. Each component is a different point through which the system can enter your app.
There are four types of components:Activity | Screen with a user interface |
Service | Performs long running operations in the background |
Content Provider | Manages a shared set of app data |
Broadcast Receiver | Responds to system-wide broadcast announcements |
Broadcast receiver makes perfect sense, and anyone coming from a Windows world thinks of services as performing background tasks already. If you consider data as content then of course a content provider provides data to the rest of the application. So the only one that has a slightly bizarre name is an Activity. If you think of an activity as a single focused thing that a *user* can do, then it makes sense.
Three of them (Activity, Broadcast Receiver, and Service) are all activated by an asynchronous message called an intent. Intents are confusing, but they are essentially an abstract description of an operation to be performed. Try using the mnemonic, "It is my intent to perform this operation." Another way to think of an intent is a description of an operation written down on a piece of paper (more on this later).
In Android an intent can be either explicit or implicit. In an explicit intent the fully qualified class name of an actual component that needs to run is on the piece of paper. Android makes sure that the component runs.
An implicit intent is a little more vague. Once again it is just a string, but it is global, and you don't want to collide with someone else's string. The implicit intents are generally reverse domain qualified (e.g. "com.mydomain.myapp.myintent") so that there are no naming conflicts.
When apps are *installed* Android takes all of the implicit intents specified in the manifest and adds them to its global table. If we go back to the piece of paper analogy, an implicit intent is a single-sheet newsletter. Applications that include that implicit intent in the filters section of the manifest are subscribing for the newsletter, and then when an app publishes the newsletter, Android makes sure that it gets to all of the subscribers.
There is an addtional type of intent called a *pending* intent. Things get a little more complicated with a *pending* intent. However it is easy to understand if we think of an intent (or piece of paper) that has been placed inside an envelope with some handling instructions, similar to inter-office mail or do not open until your birthday. The action written on the piece of paper is performed on behalf of the sender.
One set of handling instructions is the flags parameter. All of the static methods for creating a PendingIntent, like getActivity, getBroadcast, or getService, accept a flags parameter. Flags can be combined together and some only make sense in the context of the other flags. Here are the flags on PendingIntent and how they fit in with the envelope analogy.
FLAG_CANCEL_CURRENT | This is an update, throw away the old piece of paper you were working on and replace it with this new one |
FLAG_NO_CREATE | (NOTE: only relevant in combination of the CURRENT flags). If you didn't already have an envelope, ignore this one also |
FLAG_ONE_SHOT | Burn after reading |
FLAG_UPDATE_CURRENT | Don't throw the first piece of paper away, instead make these revisions to the piece of paper |
Here is a few snippets of code (C# code written using Xamarin Studio) that show how you would use an intent in practice. In this example we are creating a “Geofencing Intent”. A GeoFence is simply a location based circle that a user can enter or leave. When either of those events happen your application can be notified. Think of the example where the user wants to be reminded to “take the trash out when I get home”. The “when I get home” piece indicates a location based area. We can create a GeoFence for this area and be notified when the user enters this area.
Here is an example of of creating an IntentService using Xamarin C# code
using Android.App; using Android.Content; using Android.Support.V4.App; using Android.Gms.Location; using Android.Locations; namespace TIG.Todo.AndroidApp { [Service] [IntentFilter(new[] { "com.sdtig.Todo.WITHIN_PROXIMITY" })] public class GeofenceIntentService : IntentService { protected override void OnHandleIntent (Intent intent) { //Handle Intent } } }
Below is a snippet that shows an example of sending a PendingIntent out (see line 43)
[Service] [IntentFilter(new[] { "com.sdtig.Todo.START_LOCATION", "com.sdtig.Todo.SET_GEOFENCE" })] public class GeofencingHelper : Service, Android.Locations.ILocationListener { public override Android.OS.IBinder OnBind (Intent intent) { return null; } public override void OnStart (Intent intent, int startId) { if (intent.Action == "com.sdtig.Todo.START_LOCATION") { //Elided } if (intent.Action == "com.sdtig.Todo.SET_GEOFENCE") { SetFence(); } } public void SetFence() { bool isWithinRadius = false; foreach (var fence in fences) { float[] results = new float[1]; Location.DistanceBetween(fence.Latitude, fence.Longitude, currentLatitude, currentLongitude, results); float distanceInMeters = results[0]; if (distanceInMeters < radiusInMeters) { isWithinRadius = true; break; } } if (!isWithinRadius) { var intent = new Intent(CustomActions.TODO_WITHIN_PROXIMITY); PendingIntent pendingIntent = PendingIntent.GetService(this, 0, intent, PendingIntentFlags.UpdateCurrent); _locationManager.AddProximityAlert(currentLatitude, currentLongitude, radiusInMeters, -1, pendingIntent); } } }
And finally here is a snippet showing the MainActivy.cs file where we start an Intent service to watching for system intent's related to Location Monitoring
using System.IO; using Android.App; using Android.Content; using Android.Widget; using Android.OS; using TIG.Todo.Common; using Android.Content.PM; using TIG.Todo.Common.SQLite; namespace TIG.Todo.AndroidApp { [Activity (Label = "TIG.Todo.Android", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] public class MainActivity : Activity { private TaskManager taskManager; protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); // Set our view from the "main" layout resource SetContentView (Resource.Layout.Main); //Intent intent = new Intent (this, typeof(GeofencingHelper)); StartService(new Intent("com.sdtig.Todo.START_LOCATION")); } } }
Hopefully the analogy helped to simplify some of the more abstract Android concepts.
Saturday, July 26, 2014
Web UI Testing Part 4: Extension methods in Page Object Model
Here are some of the highlights of that solution. We created some additional extension methods for any web element to be able to perform some common functions. Because Selenium's FindElement normally only looks under an element, and we needed a way of looking above an element, we modified this hack using XPath parent axis. Another really useful function is the ability to extract table information.
public static class WebElementExtensions
{
public static IWebElement GetParent(this IWebElement element)
{
return element.FindElement(By.XPath("parent::*"));
}
public static IWebElement FindParentByClassName(this IWebElement element, string className)
{
if (element == null)
{
return null;
}
var classValue = element.GetAttribute("class");
if (classValue.Contains(className))
{
return element;
}
return FindParentByClassName(element.GetParent(), className);
}
public static List<string[]> ToTable(this IWebElement element)
{
var rows = new List<string[]>();
foreach (var tr in element.FindElements(By.TagName("tr")))
{
var thOrTds = tr.FindElements(By.TagName("th")).Union(tr.FindElements(By.TagName("td")));
rows.Add(thOrTds.Select(c => c.Text).ToArray());
}
return rows;
}
In addition to the normal page object model there are often times menus, or toolbars, that cross pages. The original way we did this was just to use the Base classes, but we soon started needing the base classes for things like steps in a wizard. So instead we moved those to extensions as well, based off the BasePage. So when we created a new page that used an exiting menu partial we could use the extension methods to call those the methods easily without any modifications. We found the easiest way to do this was based off empty interfaces, because extension methods don't really support attributes and we needed someway of describing which extension methods were legal on which objects.
public interface IHaveAdminMenu
{
}
public static class AdminMenuExtensions
{
public static void AdminMenuClickItems(this IHaveAdminMenu adminMenu)
{
var basePage = (BasePage) adminMenu;
basePage.Driver.FindElement(By.Id("itemsLink")).Click();
}
}
Sunday, July 6, 2014
Web UI Testing Part 3: The Page Object Model
Tuesday, June 24, 2014
Xamarin Forms changes the game
Thursday, June 5, 2014
Wednesday, June 4, 2014
Tuesday, June 3, 2014
Monday, June 2, 2014
New SQL Tip: SET XACT_ABORT ON
I have a new SQL Tip about SET XACT_ABORT. If you're unfamiliar with this setting, you should definitely spend three minutes and watch this tip:
CREATE TABLE t1(
col1 INT PRIMARY KEY)
GO
INSERT INTO t1
VALUES
(1)
,(2)
,(3)
,(4)-- Assuming SET IMPLICIT_TRANSACTIONS is OFF
INSERT INTO t1
VALUES(1)
INSERT INTO t1
VALUES(99)
-- Which rows get inserted?
SELECT * FROM t1-- Which rows get inserted for this explicit transaction?
BEGIN TRANSACTION;
INSERT INTO t1
VALUES
(1)
INSERT INTO t1
VALUES
(100)
COMMIT TRANSACTION;
GO-- Which rows get inserted? Did 100 get inserted?
SELECT * FROM t1-- With SET XACT_ABORT?
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO t1
VALUES
(1)
INSERT INTO t1
VALUES
(200)
COMMIT TRANSACTION;
GO
D
ROP TABLE t1
Sunday, June 1, 2014
Web UI Testing Part 2: Front-door testing tools
Sunday, May 18, 2014
Saturday, May 17, 2014
Saturday, April 12, 2014
Web UI Testing Part 1: Front-door and back-door testing
- changes to the layout template break all tests
- inability to test JavaScript manipulations of the page.