Ian Blackburn

July 2006 Entries

Even simpler Database Unit Testing with TransactionScope

Technorati Tags: ,

Roy Osherove has a well read article explaining how to use Enterprise Services to do database testing.  This is a pretty nice solution but if you are using .Net 2  then there is an even simpler way:  Using System.Transactions.TransactionScope.

Some background: When you unit test code that is making changes to a database you want a way to ensure that the database remains consistent between tests.  One way to do that is to wrap the work in a transaction and then roll it back after the test is done.

If you are using .Net 2 then you declare a TransactionScope variable then instantiate it in SetUp method:

private TransactionScope scope;

[SetUp]
public void SetUp()
{
  scope = new TransactionScope(TransactionScopeOption.RequiresNew);
}

Now simple dispose of it in the TearDown method:

[TearDown]
public void TearDown()
{
  scope.Dispose();
}

Any test will now run in a transaction.  If your database code is using multiple connections then you may need to have the MSDTC running (because the transaction will be promoted from a lightweight one to a DTC one), but apart from that you are done.

HTH

Ian

Atlas is not just the UpdatePanel! - Here's a simple Atlas Client Script example to prove it!

Most of the examples you see out there regarding Atlas involve wrapping the UpdatePanel around something, adding some triggers and seeing the magic.

That is great, but Atlas has more to offer than that because it offers a 1)whole client side framework that makes writing on the client so much nicer for those of you coming from a .net background and 2)Control Extenders that make your server side controls perform client side magic. 

Heres an example of the client stuff.  For more information on the control extenders checkout the toolkit.

Creating a Page to Display a Random Quote

Lets say you have been asked to create a web page to show a daily quote.  The information will be provided via a web service with the following method:

  • GetQuote() - returns an object with a QuoteText, Author and Url property with details of a random quote.

Displaying the Quote

  • Users should click a link on the page to display the quote.  The Author property should be displayed as a hyperlink using using the Url.

e.g.: This is the quote - Author 

  • Users should be able to change the style of the quote using a dropdownlist with the following values: small, medium, large.  Selecting this should apply a style to the quote.
  • Users should be able to make a new quote show automatically every 5 seconds if they like.

OK so lets run through this using Atlas controls...

Adding the Script Manager

First add the script manager to the page:

<atlas:ScriptManager ID="ScriptManager1" runat="server">

<Services>

<atlas:ServiceReference Path="QuoteService.asmx" />

</Services>

</atlas:ScriptManager>

We have added a reference to our QuoteService.asmx web service in the script manager.  The script manager is the only server control we are using here.

Laying Out the Page

Next lets layout the page:

<div>

<select id="StyleSelect">

<option value="small">Small</option>

<option value="medium" selected="selected">Medium</option>

<option value="large">Large</option>

</select>

<a href="#" id="HyperLink1" >Get Quote</a>

<input id="Checkbox1" type="checkbox" /> Auto Quote (every 5 seconds)

<br />

<br />

<span id="QuoteText"></span><a id="AuthorHyperLink"></a>

</div>

Ok that gives us a very basic layout to use:  

Lets add some basic styles too:

<style type="text/css">

.small

{

font-size:.7em;

}

.medium

{

font-size: 1.5em;

}

.large

{

font-size: 2em;

}

</style>

Creating the Client Side Code

Now to create the client side code:

I am going to create some vars and then initialise them in a pageLoad event that Atlas provides (add the following in a <script type="text/javascript"></script> block)

var styleSelect;

var hyperLink1;

var authorHyperLink;

var quoteText;

var timer;

var checkBox1;

function pageLoad()

{

hyperLink1 = new Sys.UI.HyperLink($('HyperLink1'));

hyperLink1.initialize();

hyperLink1.click.add(getQuote);

styleSelect = new Sys.UI.Select($('StyleSelect'));

styleSelect.initialize();

styleSelect.selectionChanged.add(changeStyle);

quoteText = new Sys.UI.Label($('QuoteText'));

authorHyperLink = new Sys.UI.HyperLink($('AuthorHyperLink'));

timer = new Sys.Timer();

timer.initialize();

timer.set_interval(5000);

timer.tick.add(timerTick);

timer.set_enabled(false);

checkBox1 = new Sys.UI.CheckBox($('CheckBox1'));

checkBox1.initialize();

checkBox1.click.add(checkBox1Clicked);

}

You'll notice a few things here:

  • Using the $ is an Atlas shortcut for getElementById
  • I am creating objects from these elements.  And these objects are part of the client Sys.UI namespace that Atlas provides. (e.g. hyperLink1 = new Sys.UI.HyperLink($('HyperLink1'));
  • These objects have their own Atlas properties, methods and events (see http://atlas.asp.net/docs/Client/default.aspx for full reference), so I can do things like the following to wire up an event:

    hyperLink1.click.add(getQuote);

Calling the Web Service

Lets have a look at how we get the quote.  The following is the mocked method to deliver the quote:

[WebMethod]

public Quote GetRandomQuote()

{

Random rnd = new Random();

Quote quote = new Quote();

quote.Author = "Fred " + rnd.Next(100).ToString();

quote.QuoteText = "Some Quote " + rnd.Next(100).ToString();

quote.Url = "http://" + rnd.Next(100).ToString();

return quote;

}

and the quote class is simply:

public class Quote

{

private string _quoteText;

public string QuoteText

{

get

{

return _quoteText;

}

set

{

_quoteText = value;

}

}

private string _author;

public string Author

{

get

{

return _author;

}

set

{

_author = value;

}

}

private string _url;

public string Url

{

get

{

return _url;

}

set

{

_url = value;

}

}

}

When we add a reference to the script manager (as we did above) then we get proxy classes to call the web service for free - so we can do the following:

function getQuote()

{

QuoteService.GetRandomQuote(randomQuoteComplete);

}

 

function randomQuoteComplete(result)

{

authorHyperLink.set_text(result.Author);

authorHyperLink.set_navigateURL(result.Url);

quoteText.set_text(result.QuoteText + " - ");

}

You'll notice here that

  • there is a callback which is called when the method is complete.  You can also add callbacks for errors, timeouts and cancel (see http://atlas.asp.net/docs/atlas/doc/services/consuming.aspx for full details of consuming web services on the client).
  • The complex type (ie. Quote) is returned and we can access it's properties using the familiar dot notation (result.Author)

Using the Timer Class

This is very simple.  We just need to enable the timer when the checkbox is clicked (we have already set up the event handler for this in the pageLoad event), then call getQuote() on every tick the timer generates:

function checkBox1Clicked()

{

timer.set_enabled(checkBox1.get_checked());

}

function timerTick()

{

getQuote();

}

Applying Styles to the Quote

The Atlas client library controls all come with classes that let you work with Css (http://atlas.asp.net/docs/Client/Sys.UI/Control/default.aspx).  Since we have already wired up the selectionChanged event for the dropdownlist to a changeStyle method, we can do the following:

function changeStyle()

{

var styleName = styleSelect.get_selectedValue();

authorHyperLink.set_cssClass(styleName);

}

OK that's it.  Hopefully that has demonstrated some of the features of the Atlas client library.  There are of course many more things you can do.  For example:

  • Data Binding
  • Declarative mark-up using Xml-Script instead of  using javascript
  • Behaviours (e.g AutoComplete behaviour)

Check out the docs for more details

HTH

Ian

GPS Sample update

Technorati Tags: ,

In my previous blog (yes I know it's been a while!) I mentioned that there is a bug in the MSDN GPS sample for windows mobile.

Turns out that is not the end of the story.

There is a further bug relating to the way the code deals with degrees when the longitude or latitude is -0.xxx which requires a refactoring to sort out.  The refactoring essential needs to make sure the DegreesMinutesSeconds class returns whether the Degrees element is negative.  If anyone wants the code let me know.

In addition to this Simon Jones contacted me via this blog to explain his similar problems and also came up with the following to get the GPS to accept a test file; thus making it much easier to unit test this sort of code:

FYI I've managed to get the GPS Intermediate Driver to accept a test file as it's input as per the instructions on
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/wce51conGPSIntermediateDriverFileRegistrySettings.asp. This means you can unit test your code in the emulator.

Here are the steps to get it working:

1. Using the Remote Registry Editor ccrededt.exe (C:\Program Files\CE RemoteTools\5.01\bin) create a new key in [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS IntermediateDriver\Drivers] to hold your GPS settings e.g "Test"

2. In [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS IntermediateDriver\Drivers] create a string value called "CurrentDriver" with value "Test"

3. In [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS IntermediateDriver\Drivers\Test] create a string value called "InterfaceType" with value "File"

4. In [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS IntermediateDriver\Drivers\Test] create a string value called "FriendlyName" with value "Test GPS"

5. In [HKEY_LOCAL_MACHINE\System\CurrentControlSet\GPS IntermediateDriver\Drivers\Test] create a string value called "File1" with value "\temp\gps.nmea"

6. Using the Remote File Viewer ccfilevw.exe (C:\Program Files\CE RemoteTools\5.01\bin) copy an NMEA file to "\temp" and name it according to the filename in step 5

7. Run your app through the emulator and the dummy GPS data *should* stream as if it were coming from an attached device...

HTH

Ian