Tuesday, August 28, 2007

Sorry, if you haven't registered already for the Sept 15 2007 Code Camp you are out of luck.  Hopefully we'll see you at the next Code Camp, we are planning one for the winter.

 

If you are attending, check out the Philly.Net site to see a list of presentations.  We've got a nice variety of presenters and presentation topics.  If you are interested in the free stuff you can get at Code Camp, check out this post.

Tuesday, August 28, 2007 8:25:59 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, August 24, 2007

I recently started playing around with WatiN (Web Application Testing in .Net) and WatiN Test Recorder.  While these are cool tools that can greatly improve the testing process, I found that there isn't a lot of information out there to help get started.  I have put together a brief tutorial on some of the basics.  I hope it helps.  I'm including code samples in this post, plus you can download the entire VS Solution and a short video below.

WatiN, pronounced "What-in", is a library that allows you to create tests for web applications.  It is based in WatiR which was created for Ruby.  Basically, you can test your web pages just like any other classes.  In my case, I'll use NUnit to control the actual tests but they are written with WatiN.  The tests run in the browser via a class named "IE".  That immediately points out one of the downsides to WatiN -- it only works with Internet Explorer.  But the tests run in a real browser so it is very accurate.

Here's a quick code sample:
            IE ie = new IE("http://localhost/somewebsite/default.aspx");
            ie.Link(Find.ById("LinkButton1")).Click();

If you run that in a test, the browser will actually open, navigate to the default page, find the LinkButton and click it.  Seems pretty simple right?  It isn't too complicated but you'll have to get used to the WatiN classes and methods.  The fact is, the tests are a pain to write.  That's where WatiN Test Recorder comes in.  All you have to do is start the recorder and the tool will begin to record your actions in the browser (there is a browser built into WatiN Test Recorder) and translate your actions into code.  If you click LinkButton1, the recorder outputs "ie.Link(Find.ById("LinkButton1")).Click();" for you!  This is a big help but it is not exactly perfect.  I have found that it doesn't get the code right and some tweaking is needed.  I'm starting to get the hang of it so the changes to the code are getting easier. 

Sample Code and Downloads:

Download my VS 2005 solution:  WatiNDemo.zip  167KB
Download my Video of WatiN Test Recorder in action:  WatiNTestRecorderDemo.avi (Right click and "save target as")  2.22MB

I created a simple data entry web application with 2 pages that pretends to register users to a web site for outdoor enthusiasts.  The first page lists the registered users, the second page is a form to register:

image image

I want to make sure my data entry page works, so I fire up WatiN Test Recorder.  The video (see the link above) shows what happens in the recorder as I step through the page  and enter the data into the web form.  Here is the code that the recorder generated for me, with line numbers added here for reference:

          1   IE ie = new IE("http://localhost:49573/RegisteredList.aspx");
          2   ie.Link(Find.ById("LinkButton1")).Click();
          3   ie.TextField(Find.ById("txtFirst")).Click();
          4   ie.TextField(Find.ById("txtLast")).Click();
          5   ie.TextField(Find.ById("txtLast")).TypeText("andy");
          6   ie.TextField(Find.ById("txtEmail")).TypeText("schwam");
          7   ie.TextField(Find.ById("txtEmail")).Click();
          8   ie.TextField(Find.ById("txtEmail")).TypeText("andy@email.com");
          9   ie.RadioButton(Find.ByName("rdoSendInfo_0") && Find.ByValue("yes")).Checked = true;
          10  ie.TableCell(Find.ByCustom("innertext", " Choose New Jersey Pennsylvania")).Click();
          11  ie.SelectList(Find.ById("ddlState")).SelectByValue("Pennsylvania");
          12  ie.SelectList(Find.ById("ddlCounty")).Click();
          13  ie.SelectList(Find.ById("lstHobbies")).Click();
          14  ie.SelectList(Find.ById("lstHobbies")).Click();
          15  ie.SelectList(Find.ById("lstHobbies")).Click();
          16  ie.SelectList(Find.ById("lstHobbies")).Click();
          17  ie.Button(Find.ById("btnSubmit")).Click();
          18  ie.Link(Find.ByUrl("javascript:__doPostBack('GridView1','Select$0')")).Click();
          19  ie.Link(Find.ById("LinkButton1")).Click();

Fixing the Generated Code:

  • Line 1 and 2 are good:  Open Internet Explorer and navigate to my page.
  • Line 3, 4, 7, and 10 are not really needed but it won't cause any trouble.  The clicks seem to be irrelevant.
  • Line 5 and 6 are just wrong.  I put the text "andy" in the textbox named txtFirst, and "schwam" in txtLast.  I can easily fix them:  
    • ie.TextField(Find.ById("txtFirst")).TypeText("andy");
    • ie.TextField(Find.ById("txtLast")).TypeText("schwam");
  • Line 9 throws this exception if you let it run: "WatiN.Core.Exceptions.ElementNotFoundException: Could not find a 'INPUT (radio)' tag containing attribute name with value 'rdoSendInfo_0'".  It should be Find.ById, not Find.ByName.  This works instead:
    • ie.RadioButton(Find.ById("rdoSendInfo_0")).Checked = true;
  • Line 11 is good
  • Line 12.  Notice no county is selected. Try this:
    • ie.SelectList(Find.ById("ddlCounty")).SelectByValue("Delaware");
  • Lines 13, 14, 15, and 16 are just clicks but nothing is selected.  Try this:
    • ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Hiking");
    • ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Camping");
    • ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Mountain Biking");
    • ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Kayaking");
  • Line 18 is correct but worth mentioning.  This selects the first row in the grid which causes the application to display the users detail in the grid.

That doesn't seem to good for a first shot!  But even with all of the mistakes, I'd rather start with the generated code then nothing at all, especially if this was a longer, more complicated test.  Plus, I admit there are features of the recorder that I am not familiar with so maybe it would work better if I actually knew what I was doing! 

AJAX Issues:

Technically, the changes I made are correct but it still won't work right.  I am using ASP.Net Ajax to call back to the server when the state (ddlState) changes.  I'm populate a list of counties (ddlCounty) on the server.  When you run the test it goes so fast that it tries to select the county before the drop down list is loaded!  I found some documentation about a WaitUntil() method but I couldn't get it to work.  So I did it the old fashioned way and put the thread to sleep:

            ie.SelectList(Find.ById("ddlState")).SelectByValue("Pennsylvania");
            System.Threading.Thread.Sleep(100);
            ie.SelectList(Find.ById("ddlCounty")).SelectByValue("Delaware");

Validation:

After the submit button is clicked, the application returns to the list of users.  Since I am writing a test, I should validate the results.  I'll add in a few asserts:

            Assert.AreEqual("Andy", ie.TextField(Find.ById("txtFirst")).Text);
            Assert.AreEqual("Schwam", ie.TextField(Find.ById("txtLast")).Text);
            Assert.AreEqual("me@email.com", ie.TextField(Find.ById("txtEmail")).Text);

The Final Test Class:

The solution contains a class library with a class Tests . Using NUnit, I can execute the test easily.

using WatiN.Core;
using NUnit.Framework;

namespace Tests
{
    [TestFixture]
    public class Tests
    {
        [Test]
        public void FirstTest()
        {
            IE ie = new IE("http://localhost/WatinDemoSite/RegisteredList.aspx");
            ie.Refresh();
            ie.Link(Find.ById("LinkButton1")).Click();
            ie.TextField(Find.ById("txtFirst")).TypeText("Andy");
            ie.TextField(Find.ById("txtLast")).TypeText("Schwam");
            ie.TextField(Find.ById("txtEmail")).TypeText("me@email.com");
            ie.RadioButton(Find.ById("rdoSendInfo_0")).Checked = true;
            ie.SelectList(Find.ById("ddlState")).SelectByValue("Pennsylvania");
            System.Threading.Thread.Sleep(100);
            ie.SelectList(Find.ById("ddlCounty")).SelectByValue("Delaware");
            ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Hiking");
            ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Camping");
            ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Mountain Biking");
            ie.SelectList(Find.ById("lstHobbies")).SelectByValue("Kayaking");
            ie.Button(Find.ById("btnSubmit")).Click();

            //VALIDATION

            ie.Link(Find.ByUrl("javascript:__doPostBack('GridView1','Select$0')")).Click();

            Assert.AreEqual("Andy", ie.TextField(Find.ById("txtFirst")).Text);
            Assert.AreEqual("Schwam", ie.TextField(Find.ById("txtLast")).Text);
            Assert.AreEqual("me@email.com", ie.TextField(Find.ById("txtEmail")).Text);

        }
    }
}

Running The Tests:

I use ReSharper from JetBrains which makes my life easier in so many ways.  One of which is that it includes a tool to run unit tests.  The tests within the Visual Studio solution included in this post work great when run through ReSharper.  But I found that when I ran the tests with NUnit GUI directly I got an exception:

Tests.Tests.FirstTest : System.Threading.ThreadStateException : The CurrentThread needs to have it's ApartmentState set to ApartmentState.STA to be able to automate Internet Explorer.

There are some posts out there about resolving this issue but I have a better solution.  Either install ReSharper or install UnitRun, a free tool that runs tests (also from JetBrains).  While I haven't tested UnitRun, I expect it will work the same as the ReSharper solution.

Friday, August 24, 2007 11:57:43 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [5]  |  Trackback
 Thursday, August 23, 2007

It's official.  You can now register for Philly.Net Code Camp 2007.2.

On Sept. 15, 2007 we'll have 25 sessions on .Net related topics.  Check out the web site for more information including a preliminary list of topics and presenters.

Also, check out this blog post for more information on our generous corporate contributors and the prizes that we'll have.

Registration opened last night but remember, last time it filled up in less then a day!  Register now, don't get shut out.

Thursday, August 23, 2007 9:38:59 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, August 22, 2007

Presenter:  Adrian Peoples, Diamond Technologies

Topic:  Delivering a Hybrid MOSS 2007 Implementation using VS.NET 2005, ASP.NET, C#, Microsoft SharePoint Designer 2007, Microsoft Excel 2003, Web Services, and WSS 3.0

Adrian started right off by showing us a live site that demonstrates the proof of concept project that Diamond Technologies created for a client.  The client wanted data entry through Excel 2003, stored it in SQL Server 2005, and accessing the data through MOSS 2007.  In this demo, Adrian showed some interesting techniques for using MOSS.  He showed how the MOSS application creates dynamic sharepoint sites using WSS 3.0.  He demonstrated how to create a .aspx page that will run inside a sharepoint site.

 

Code Camp Registration is OPEN!

In between sessions, Bill demonstrated how he sets up the meetings on the web site.  He even opened up Code Camp registration during the meeting!

 

Presenter:  Kevin Goff, Common Ground Solutions

Topic:  LINQ

LINQ is a really exciting new technology.  Language Integrated Query (LINQ) is a new addition to the .Net Framework.  It is built in to VS2008 which is still in Beta.  Kevin suggests running it in a virtual machine only!  He showed 4 of the key types of LINQ:  LINQ to SQL, LINQ to XML, LINQ to DataSets and LINQ to Objects.  LINQ to SQL allows a programmer to write .Net code in a strongly typed manner and access data in a SQL db.  He used sqlmetal (a cmd line tool) to create objects for him.  It is similar to a strongly typed dataset but it is a class.   The syntax is similar to SQL but still quite different.  LINQ to Objects is really cool.  It allows you to execute "sql like" queries on collections of objects.  Kevin also showed how you can take a LINQ result and load it into a DataSet using reflection.  Since Kevin was running a little late, there wasn't much time to show LINQ to DataSets and XML but he did a quick run through on the basics.

 

LINQ is pretty cool stuff.  We'll all be using it soon so it is a good idea to start reading up.

 

Hopefully I'll have Kevin's source code to post soon.

Check out his blog for all sorts of information.

 

here are some resources that Kevin recommends:

http://thedatafarm.com/blog

http://oakleafblog.blogspot.com 

http://codebetter.com

http://www.linqdev.com/publicportal

http://weblogs.asp.net/scottgu

 

 

Meeting Sponsor: Diamond Technologies... Thanks for the sandwiches and snacks!  

Additional Door Prizes courtesy of:  wrox_4c , Microsoft

Wednesday, August 22, 2007 8:04:05 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, August 21, 2007

(Updated Sept. 5)

Philly.Net is proud to present Code Camp 2007.2 on September 15. 2007 along with our Gold Partners:

Infragistics SourceGear
Neudesic Phillydotnet_gif

Our partner organizations for this event are PhillySharePoint and PSSUG.

 

Swag/Prize contributors:

Here is a preliminary list of companies that are helping us with Code Camp:

Addison-Wesley Books, T-shirts, Canvas Bags
Apress Books, T-Shirts, etc
CoDe Magazine Magazine for each attendee*
CodeSmith Tools 5 Licenses to CodeSmith
ComponentArt Software license
Diamond Technologies Gift Card and other swag
Dundas 10 Dundas Calendar Licenses, 1 Hoodie, 1 Dundas Gauge License, etc
Google T-Shirt for each attendee*
JetBrains 5 Licenses for ReSharper
Microsoft Vista, Office, Expression Web, and other goodies
O'Reilly Books
Red-Gate an iPod and Red-Gate Software
SQL Server Magazine Subscription for each attendee!
TechSmith Snagit, Camtasia Studio, trial software, etc
Wrox Books, T-Shirts, Water Bottles
   

 

Stay tuned for more information...

 

* While supplies last

Tuesday, August 21, 2007 9:08:36 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [1]  |  Trackback

Here's a heads up on two events coming soon.  This is a great opportunity to learn about Silverlight and Expression Studio from three of the local Microsoft Developer Evangelists:  Danilo "Dani" Diaz, G. Andrew Duthie, and Zhiming "Z" Xue.  Check out the links for more information and to register.

Each event has two sessions:

  • Building Rich Interactive Applications with Microsoft Silverlight
  • Delivering Rich Web Experiences Using Microsoft Expression Studio

 

What:MSDN Roadshow
When:Friday, September 14, 2007 8:00 AM to 12:00 PM
Where:Microsoft, Pittsburgh

 

What:MSDN Roadshow
When:Thursday, October 18, 2007 8:00 AM to 12:00 PM
Where:Microsoft, Malvern
Tuesday, August 21, 2007 1:11:02 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, August 10, 2007

Philly.Net is proud to present Code Camp 2007.2 on September 15. 2007

Our partners for this event are PhillySharePoint and PSSUG.

 

Here is an update on some of the contributions and swag we're getting for Code Camp:

Gold Level:

We are really excited to have two well known companies helping out.

 Infragistics SourceGear

Thanks to their contributions, we'll have great food to eat and excellent prizes!

 

Swag/Prize contributors:

Here is a preliminary list of companies that are helping us with Code Camp:

Addison-Wesley
CoDe Magazine
ComponentArt
Diamond Technologies
Dundas
Google
Microsoft
O'Reilly

Red-Gate
JetBrains
RJB Tech
TechSmith
Wrox

 

As things are finalized, I'll post specific information about the cool prizes we'll be giving out!

Friday, August 10, 2007 12:52:45 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, August 04, 2007

I've gotta start by saying I love Vista.  A lot of people I talk to are still scared of Vista but I have really enjoyed using it.  I'm no expert on the features but I did blog about a few that I liked right out of the gate.  Lately,  one thing that makes me crazy is the TrustedInstaller.exe.  First, you should understand that I built my own machine and I guess either my CPU fan or the box itself (or both) must suck.  Because when my CPU is cranking, the fan revs up and rattles the entire box.  It is really annoying!  And because of this, it is obvious to me every time TrustedInstaller.exe is running.  This thing typically runs at 48% of my CPU and lasts for 15 minutes or so.  I don't know why it isn't throttled back a bit, it doesn't make sense to me.

Anyway, when I first figured out that TrustedInstaller was the culprit, I did some web searching and found a blog post by Scott Hanselman.  I was really glad that I wasn't the only one suffering, especially someone that I respect like Scott (sorry Scott).  But it validated me, that I wasn't doing something wrong myself. 

Interestingly, when I looked up his blog post today to include it here, I read something that stood out to me:

"When I see things like this, I think "If I worked for Microsoft, fixing this problem could be a HUGE opportunity.""

Posted 5/28/2007 on Scott's Blog

Wow, that is awesome because I remembered another post on Scott's blog from which I quote:

"I'm going to work for Microsoft. There, I said it. I'm going to work for ScottGu's team in the Developer Division."

Posted 7/21/2007 on Scott's Blog

OK, I am pretty sure ScottGu's team isn't responsible for the TrustedInstaller.  But Scott (Hanselman), can you PLEASE walk down the hall and talk to someone!

Saturday, August 04, 2007 10:32:57 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Friday, August 03, 2007

Here's a cool features of the .Net Framework 2.0 that I think isn't too widely known.

Did you know that you can have a public property but restrict the Set portion of it as Protected?  That gives the developer an extra level of control so that derived classes have the ability to set the property's value but other classes can only get the property's value.  Check out this sample:

    public class BaseClass
    {
        private string _myValue;

        public string MyValue
        {
            get { return _myValue; }
            //NOTE THE SET IS PROTECTED!
            protected set { _myValue = value; }
        }
    }

    public class ExtendedClass : BaseClass
    {
        public void DoSomething()
        {
            MyValue = "some value";
            string s1 = MyValue;
        }
    }
    public class DifferentClass
    {
        public void DoSomething()
        {
            BaseClass b = new BaseClass();
            string s = b.MyValue;
            b.MyValue = "some value";  //THIS GETS A COMPILER ERROR!
        }
    }

You can see that in ExtendedClass I can use the property to GET or SET, but in DifferentClass I can only GET.

Here is the error that Visual Studio reports:

PropertyError

 

I should mention that Intellisense did not show this error (with the squiggly lines) instantly as it usually does.  I needed to compile the project before Visual Studio recognized something was wrong.  And in case you are wondering...Yes, this feature is included in VB.Net too.  Although I should mention that in VB.Net, Intellisense showed me the error even before I compiled.  Darn, I hate to say nice things about VB.Net.  Here is a VB.Net version:

 
Public Class BaseClass
    Private _myValue As String

    Public Property MyValue() As String
        Get
            Return _myValue
        End Get
        Protected Set(ByVal Value As String)
            _myValue = Value
        End Set
    End Property
End Class
Public Class ExtendedClass
    Inherits BaseClass

    Sub DoSomething()
        Dim s1 = MyValue  'GET WORKS
        MyValue = "Some Value" 'SET WORKS
    End Sub

End Class
Public Class DifferentClass
    Sub DoSomething()
        Dim b As New BaseClass
        Dim s1 As String
        s1 = b.MyValue  'GET WORKS
        b.MyValue = "Some Value" 'SET GETS A COMPILER ERROR!!!!
    End Sub

End Class

Hopefully this is helpful to you!

Friday, August 03, 2007 8:33:37 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [1]  |  Trackback