Welcome to Manicprogrammer Sign in | Join | Help

JsUnit + Accuracy

After I got my tests passing in JsUnit, I decided I needed to automate the execution of the JavaScript Unit Tests for Fjords(more on that in a later post). So, the only way I could think of doing that was to drive the browser to the JsUnit Test Runner page and type the correct parameters. Thank god I have an amazing Browser Driver called Stormwind.Accuracy.

Introduction

You can check how the JsUnit test runner looks here. But in the local version you get to choose the path to the test (in a textbox). "So", I thought, "It's pretty easy to automate that. I just write the test path in the textbox and click on run. Then I check that there were zero failures. How hard can that be?".

Whenever you finish a sentence with "How hard can that be?" you know that you are in for a world of pain. First thing that I noticed is that the JsUnit test runner uses a FrameSet, but not only that, it uses a FrameSet inside a FrameSet. That tends to be hard for Accuracy, since you need to specify the frame you want to find the control in. The thing here is I had never done any code with frames inside frames.

I was thrilled to see that the code in Accuracy is so simple that I managed to change the code to use hierarchical frames in no time. Now you can just say I.AmIn("some frame name").Frame or I.AmIn("Some Frame>Some Sub Frame>Some Inner Frame").Frame and it will put you inside the correct frame. This way I got to automate JsUnit properly.

The Test Fixture

Let's check what the JsUnitTestFixture looks like:

   1:      public abstract class JsUnitTestFixture : AcceptanceTestFixture
   2:      {
   3:          [Test]
   4:          public void ShouldRunTests()
   5:          {
   6:              //Context.Current.DebugMode = true;
   7:              Context.Current.ElementNamingStrategy = new CustomNamingStrategy();
   8:              var story = Story
   9:                  .AsA("Web Site User")
  10:                  .IWantTo("Unit test JavaScript using the " + TestPageUrl + " Page")
  11:                  .SoThat("I can verify that my JavaScript code is correct");
  12:   
  13:              var url = Path.Combine(Context.Current.RootUrl, "UnitTests/" + TestPageUrl);
  14:   
  15:              story.WithScenario("The tests run")
  16:                  .Given(I.GoTo("Js Unit Test Runner Page"))
  17:                  .And(I.AmIn("Main Frame>Main Data").Frame)
  18:                  .When(I.Fill.TextBox("Test File Name").With(url))
  19:                  .And(I.Click("Run Button").Button)
  20:                  .Then(I.AmIn("Main Frame>Main Status").Frame)
  21:                  .And(I.WaitFor("Status: Done").Message)
  22:                  .And(I.AmIn("Main Frame>Main Counts>Main Counts Errors").Frame)
  23:                  .And(I.See("Errors: 0").Message)
  24:                  .And(I.AmIn("Main Frame>Main Counts>Main Counts Failures").Frame)
  25:                  .And(I.See("Failures: 0").Message);
  26:          }
  27:   
  28:          public abstract string TestPageUrl { get;}
  29:      }
  30:   
  31:      internal class CustomNamingStrategy : INamingStrategy
  32:      {
  33:          public string Resolve(ElementType type, string key)
  34:          {
  35:              return string.Join(string.Empty, key.Split(' '));
  36:          }
  37:      }

Oh, that's right, Accuracy allows you to specify the naming strategy you want. In this case, none!

So we have one abstract property saying what Test Url is your test case in, and one Test which just runs the tests in that page. I think the code is pretty self-explanatory (one of the main advantages of using Accuracy).

Now let's check one of my test classes:

   1:      [TestFixture]
   2:      public class StormwindFjordsBusTest : JsUnitTestFixture
   3:      {
   4:          public override string TestPageUrl
   5:          {
   6:              get { return "StormwindFjordsBusTests.html"; }
   7:          }
   8:      }

Woot?! That's it? How come? This test doesn't have any assertions!!!

Calm down my hasty friend. Remember that your test is written in the html form. This is just a way to automate the run of those tests.

I could run all of them in the same Unit Test, but if I did that, I'd never know which ones are broken. So, that's why I have one JsUnitTestFixture for each of my Test Pages. There's just one last thing missing, the JsUnitTestRunnerPage, which is shown here and must be initialized in Accuracy.

   1:      public class JsUnitTestRunnerPage : Page
   2:      {
   3:          public JsUnitTestRunnerPage()
   4:              : base("/UnitTests/jsUnit/TestRunner.html")
   5:          {
   6:              Register.Textbox("Test File Name");
   7:          }
   8:      }

Conclusion

That's all you need my friend to have your JsUnit tests being run together with all your other unit tests.

Now I can really write as many JsUnit tests as I want to.

Hope that helps!

#146

JSUnit

These days I've been doing more and more JScript, thanks to JQuery and ExtJs. I've been moving more and more of the application logic to the client side. That has some advantages and some disadvantages, which are clearly out of the scope of this post. The main disadvantage for me has always been that it's hard to unit test JavaScript. Until yesterday I thought it was impossible, but not anymore. Enter JSUnit.

Introduction

JSUnit allows you to easily unit test your JavaScript code. There are a few catches, though.

1) You should do Object-Oriented JavaScript in order to do that.

2) Your test classes have to be html pages with some fixed stuff.

Let's check each of them.

Object-Oriented JavaScript

What do I mean by that? I'll show it. It's easier to demonstrate by example.

Let's say I have this code:

   1:  <script> 
   2:    if (myVar > 0){   
   3:      document.greaterThanZero = true;   
   4:    }
   5:    else{
   6:      document.greaterThanZero = false;
   7:    }
   8:  </script>

This code is very hard to unit test, since we don't have anything to call on in our test. Now let's say I rewrite that to be:

   1:  <script> 
   2:    myClass = function(){   
   3:      this.checkGreaterThanZero = function (myVar){   
   4:        if (myVar > 0){   
   5:          document.greaterThanZero = true;   
   6:        }
   7:        else{
   8:          document.greaterThanZero = false;
   9:        }
  10:      };
  11:    }   
  12:  </script>

Now that is easy to test. That's what I call Object-Oriented Javascript. You encapsulate your javascript code in classes and methods, in a way that makes them easier to test (and to use). Now let's get back to JSUnit.

Test Classes

Your test classes have to follow some conventions. From the JSUnit website:

A test page must "include" the jsunit/app/jsUnitCore.js JavaScript file; this file is the JsUnit engine. (This corresponds to extending the TestCase class in JUnit.)
That is, the document's <head> must contain the statement
<script language="JavaScript" src="jsUnitCore.js"></script>
Of course, you may need to change this to point at jsUnitCore.js if you are in a different directory. For example, since the JsUnit self tests live in jsunit/tests, they point at "../app/jsUnitCore.js".

You also need to name all your tests starting with "test", so JsUnit can automatically add them. For more information check the JsUnit documentation.

What this means is that if we wanted to test the above code, we would have a test file like this:

   1:  <html>
   2:   <head>
   3:    <title>Test Page for myClass.checkGreaterThanZero(value)</title>
   4:    <script language="javascript" src="jsUnitCore.js"></script>
   5:   
   6:    <!-- This is the file that contains our class! -->
   7:    <script language="javascript" src="myJsScripts.js"></script> 
   8:   </head>
   9:   <body>
  10:    <script language="javascript">
  11:      function testWithGreaterThanZero() {
  12:        myClass.checkGreaterThanZero(4);
  13:        assertEquals("4 is greater than zero", true, document.greaterThanZero);
  14:      }
  15:      function testWithZero() {
  16:        myClass.checkGreaterThanZero(0);
  17:        assertEquals("0 is not greater than zero", false, document.greaterThanZero);
  18:      }
  19:      function testWithLowerThanZero() {
  20:        myClass.checkGreaterThanZero(-10);
  21:        assertEquals("0 is not greater than zero", false, document.greaterThanZero);
  22:      }
  23:    </script>
  24:   </body>
  25:  </html>
  26:   

That page unit tests the code that checks if a number is greater than zero for the three possible scenarios (greater than zero, zero and lower than zero).

Now that our test page is done, you just have to run it in the provided testRunner.html page that comes with JSUnit. It is pretty straightforward.

Conclusion

I can go back to have some of my application's logic live in Javascript, as long as I can unit test it. I hope this is helpful. In my next article I'll show how to make your JSUnit tests part of your NUnit run using Stormwind.Accuracy.

#145

Posted by heynemann | 1 Comments
Filed under ,

ExtJs + Monorail + Community Contributions = Success!

I tend to write titles using additions and equals... Hmm... Guess I like simple math... Who knows?

Anyway, I want to stress out today how cool I find Monorail right now! I always thought it was a cool framework, but after I wired my controllers through Windsor (which allowed me to use my repositories, services and factories in the controllers), got Restful APIs in my controllers (yes, you read that right, and I'm telling you how) and got ExtJs wired up, I've been thrilled with it!

So, without further ado, let's check it out!

Introduction

ExtJs is an amazing JavaScript framework. If you haven't tried it, stop reading now and go check it out. It is all you ever wanted in web usability. It's Web 2.0 done proper.

I specially love the grid control, which gives you all sorts of built-in functionality, like paging, ajax update, templating of rows, row selection, sorting per column, column hiding and more.

One of the most amazing features is that it takes an URL as data source, as long as the url renders XML Content-Type. This goes hand in hand with the ability of MonoRail of invoking controller actions using an URL. So all you need to do is create an action that renders XML and change the Content-Type of the Request to "text/xml" (or something like that), right?

Or you could...

Restful Controllers

One of the things that motivate me to keep doing Open-Source work is that sometimes you just think: "Thank god someone took the time to do that!". This just happened yesterday when I stumbled on the Monorail Rest Support. This is a contrib project in the MonoRail trunk. This very nice project will allow you to use C# 3.5 to generate different responses to an action. What does that mean? Let's see an example:

   1:  RespondTo(format =>
   2:              {
   3:                  format.Xml(xml => xml.Serialize(entities));
   4:                  format.Html(html => html.DefaultResponse());
   5:              });

What that means is that if my action is accessed using a Content-Type of XML MonoRail returns an XML Serialization of the entities I passed in (a simple IList<WhateverType>), which can be consumed by whoever needs it, in my case the ExtJs grid. Now, if someone requests my action using the regular content type of text/html, the regular flow of MonoRail takes place, rendering whatever view is associated with my controller. Now, is this neat, or WHAT?

My point about Open-Source is that I don't know that much about MonoRail (not yet at least) to be able to craft that Restful Controller API. Don't get me wrong, I always wanted that in MonoRail, I do get a Restful API, and I'd probably would be able to create it if I wanted to(the code is surprisingly straightforward, I advise you to check it out). The GREAT thing is that I don't have to, since there's an active community of very bright people around Castle Project. That's what I dream happens with Stormwind Project (which is largely inspired and motivated by Castle Project).

Anyway, enough of that and let's get to the code. I'll show code that uses a repository to retrieve some Tenents (repository code is off the scope of this post, but I trust you know how to get some entities out of your data store, right?), then uses that collection to respond to an ExtJs grid.

The Controller

Let's start with the controller. Let's create a simple controller called TenentManagementController:

   1:  public class TenentManagementController : RestfulController
   2:      {
   3:          private readonly ITenentRepository tenentRepository;
   4:   
   5:          public TenentManagementController(ITenentRepository tenentRepository)
   6:          {
   7:              this.tenentRepository = tenentRepository;
   8:          }
   9:   
  10:          public void Index()
  11:          {
  12:              
  13:          }
  14:   
  15:          public void GetListOfTenents()
  16:          {
  17:              RespondTo(format =>
  18:              {
  19:                  format.Xml(xml => xml.Serialize(tenentRepository.FindAll()));
  20:              });
  21:              CancelView();
  22:          }
  23:      }

What does this controller do? First it has an action called Index, which actually renders our grid. Then there's the action the grid calls to data bind itself to: GetListOfTenents.

This controller inherits from RestfulController. You can use this controller if you add a reference to Castle.MonoRail.RestSupport.dll to your project. You can find that project in here. It's an amazing piece of work, and if you can contribute to it, please do. I know that as soon as I need something that is not there (and I understand the code any better) I'm contributing. It's very easy to submit a patch to Castle. Just give it a try, you might even like it!

The View

Then, let's check the Index.vm view.

   1:  <script>
   2:  Ext.onReady(function(){
   3:      
   4:      // create the Data Store
   5:      var store = new Ext.data.Store({
   6:          // load using HTTP
   7:          url: '$siteRoot/TenentManagement/GetListOfTenents.ashx',
   8:   
   9:          // the return will be XML, so lets set up a reader
  10:          reader: new Ext.data.XmlReader({
  11:                 // records will have a "Tenent" tag
  12:                 record: 'Tenent',
  13:                 id: 'Id'
  14:             }, [
  15:                 // set up the fields mapping into the xml doc
  16:                 // The first needs mapping, the others are very basic
  17:                 {name: 'Id', mapping: 'Id'},
  18:                 'Name',
  19:                 'CreatedOn'
  20:             ])
  21:      });
  22:   
  23:      // create the grid
  24:      var grid = new Ext.grid.GridPanel({
  25:          store: store,
  26:          columns: [
  27:              {header: "Name", width: 120, dataIndex: 'Name', sortable: true},
  28:              {header: "CreatedOn", width: 180, dataIndex: 'CreatedOn', sortable: true}
  29:          ],
  30:          sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
  31:          viewConfig: {
  32:              forceFit: true
  33:          },
  34:          height:210,
  35:          split: true,
  36:          renderTo: 'results'
  37:      });
  38:   
  39:      grid.getSelectionModel().on('rowselect', function(sm, rowIdx, r) {
  40:          alert(r.data.Id);
  41:      });
  42:   
  43:      store.load();
  44:  });
  45:  </script>
  46:   
  47:  <div id="results">
  48:  </div>

If you ignore all the noise, let's concentrate in the very interesting points here:

  1. The Ext.onReady function. This is a function that's invoked after the DOM has finished loading. That's perfect for us, since we want our Grid to be initialized as soon as possible.
  2. The Ext.data.Store class. This class is responsible for data binding your XML data to the grid, by translating the XML to a column-based data structure understood by Ext.grid. I'm sure you can check on the comments or on Ext documentation (which is one of the best I've ever seen) to understand how to do it.
  3. The Ext.grid.GridPanel class, which is the one that actually renders the grid. Again, checking Ext documentation is your best bet, since I can hardly explain it as well as they do. This one basically sets the look & feel of your grid. Notice the renderTo attribute. That tells that this grid should be rendered inside the element with id of 'results' (our div).
  4. The grid.getSelectionModel().on('rowselect') event. This happens whenever the users click on a row. You get back the data entity (the record) that was used to bind that row (EAT THAT, GRIDVIEW!). This way you're able to retrieve any sensible data you need in order to load details in another window, save something or whatever you need to do with that data.
  5. The SINGLE most important line of them all: store.load();. This is the code that actually calls on the data store to update itself using whatever XML is returned by the url specified. The amazing thing here is that you can call store.load() as many times as you like, so if you update some data that's in the grid, just call store.load() and you get fresh data.

Conclusion

Now there's only a few more steps involved...Oh...No...Wait... It's done! God damn it! I wanted one of those huge posts that everyone go WOW because they won't actually take the time to read, but MonoRail and ExtJs are too simple to give me enough horsepower for that.

So if you just execute TenentManagement/index.ashx (in my case, since I don't use the .castle extension), you will see a very nice 2-column grid with the data returned by your  controller action. Is that cool or what? Did you know you could implement KILLER-Looking, FEATURE-INTENSIVE Grids in like 5 minutes? Knowing the right tools makes a lot of difference, now doesn't it?

For the nitpickers of the day who are saying now "I won't do that because ExtJs is a paid framework, so I would have to pay for the license".

First of all, you do build software, don't you? You do like to get paid to do that, right? Why do you think they should just give it to you for free, if you don't do it yourself? How about donating your salary to charity?

Second, ExtJs is WAY cheaper than writing all that stuff yourself. It almost feels like you are ripping them off, and not the other way around as you might be thinking.

So if you are feeling that way, stop being a cheap developer and understand that the huge amount of time this framework will save you just pays the prices of the licenses itself.

I hope that's helpful for someone out there. If you need anything, just shout here in the comments, but I encourage you to try both Castle Project and ExtJs communities. Both very active and helpful.

#144

Amazing Results

It's been only 2 days after I first implemented my new exception throwing mechanism, and I already feel an enormous difference. It's not just having the exceptions with better messages per se, it's actually having to think why I'm throwing that exception and how would I tell whoever is getting that exception what he/she must do in order to fix the wrong behavior.

Amazing! I love tools that make me think even more about stuff I'm doing.

#143

Posted by heynemann | 0 Comments

Writing better exception Strikes Back!

Hmmm, as pinpointed by my good friend Claudio Figueiredo, the compiler isn't very thrilled with my last syntax:

   1:  public string MyCode(){
   2:    try{
   3:      return "some value";
   4:    }
   5:    catch(System.Exception ex){
   6:      Throw
   7:           .WithMessage("something")
   8:           .WithInnerException(ex)
   9:           .Exception<InvalidOperationException>();
  10:    }
  11:  }

You actually get a compiler error saying you need to return something, or something like that. That's because there's no way of telling dumb ol' compiler that the Throw.Exception<ExceptionType> method is actually a replacement for throw.

Ok, after I got over being angry at the compiler, I decided on having a different syntax (not as neat as the first one, but accomplishes the same):

   1:  throw NewException.WithMessage("Something happened")
   2:                    .Because("Why did this happen")
   3:                    .WithWorkaround("What can I do about it")
   4:                    .Of<InvalidOperationException>();

Hope it helps!

#142

Posted by heynemann | 7 Comments

Why can't I write better exceptions for myself?

Intro

After spending some time debugging an exception thrown by a code written by myself (I know, duh!), I was wondering why the hell can't I write better exception messages. I mean, just the exception type is clearly not enough. I'll demonstrate:

Scenario

I have a class that uses a configuration from AppSettings called "MyConfig". If I can't find the Configuration (if it's null or empty in the app.config or web.config) I throw an exception like this:

throw new InvalidOperationException("MyConfig cannot be null or empty");

Problem

I know that I could expand on that message and improve it so that it would be actually helpful. But as I always do, I started wondering why is that. Why I don't write the correct way the first time around? I know for sure that it would save me countless hours wasted on debugging. Or get a custom exception type for each scenario, but I'm lazy (more on that in the conclusion).

Solution

So the best solution I found was to design a fluent interface to wrap what I think a good exception message should be. The result is explained below.

Fluent Interface for Exception Throwing in Stormwind.Common

Right now this is what an exception throwing looks like, in its most comprehensive form:

   1:  Throw.WithMessage("Something happened")
   2:       .WithWhy("Why did this happen")
   3:       .WithWorkaround("What can I do about it")
   4:       .WithInnerException(new InvalidOperationException("some inner exception message"))
   5:       .Exception<InvalidOperationException>();

Now, using positioned arguments for exception constructors:

   1:  Throw.WithMessage("Something happened")
   2:       .WithArgument(0, "Parameter Name")
   3:       .WithWhy("Why did this happen")
   4:       .WithWorkaround("What can I do about it")
   5:       .Exception<ArgumentNullException>();

At this point you would ask me:

Hmmm...Don't know... Too much code, dude... I don't want to write all that just to throw an exception... I get paid by the hour you know?

Yes, I do know that. And that's why you can use just as much information as you want to:

Throw.WithMessage("Something happened").Exception<InvalidOperationException>();

I don't think I will, though. I really like being able to specify why and what to do in case an expected exception is thrown. This way I don't shoot myself (and specially anyone that's using my code) in the foot again.

Conclusion

I'm a lazy programmer and I need my tools to push me in the right direction. That's just how I am... Nothing I can do about it, now is there?

If you want to try that code by yourself just do "svn co http://svn.stormwindproject.org/svn/Stormwind.Common/" and open the solution file in \Trunk\Baseline. The Throw class is in the Stormwind.Common.Core assembly.

Opinions?

#141

Posted by heynemann | 2 Comments

Relative Path + SQLite on ASP.Net = Problem

SQLite is a very nice light-weight embedded database. It's great for testing and it even provides an in-memory database (more on that in another post).

I am using it in a new project of mine. I wanted to have the database file under the web site structure. So all I needed to do was set the connection string to:

Data Source=myDb.db;New=True;UTF8Encoding=True;Version=3;

Right? Wrong!

This path looks for the current directory, which in my case is the solution folder (don't ask!). So I thought: "Well, I'll just use a relative path instead."

Now I got it, right? Wrong!

After a little digging, I found out that this is the path you should use:

Data Source=|DataDirectory|fjords.db;New=True;UTF8Encoding=True;Version=3;

The |DataDirectory| token maps to the App_Data folder in your web application. Finally it works.

Hope this saves some headaches!

#140

Posted by heynemann | 0 Comments

Stormwind.Accuracy - Part 4

Well, continuing the saga I came to the RadioButtons. These are quite tricky, since RadioButtons are elements that have different Ids, same names and, as I'll show, weird values.

If you are just doing your own HTML inputs then you can specify all that stuff and Accuracy would work fine. But I want to analyze two common approaches in WebForms here: RadioButton Web Control and RadioButtonList Web Control.

RadioButtonList Web Control

Well, apparently RadioButtonList renders pretty good HTML, with the values you specified and all, so all you have to do in order to fill it is:

   1:  I.Select("My Radio Button Name").RadioButton.WithValueOf("Any given value")

That's pretty simple, huh? Well there's a lot of magic happening behind the scenes here, hehehe.

Several RadioButton Web Controls sharing the same GroupName

Now this one is trickier, because when you do that this is what WebForms renders:

   1:  <input id="rdbTestOption1" type="radio" name="rdbTestOptions2" value="rdbTestOption1" /><label for="rdbTestOption1">Test1</label>
   2:  <input id="rdbTestOption2" type="radio" name="rdbTestOptions2" value="rdbTestOption2" /><label for="rdbTestOption2">Test2</label>
   3:  <input id="rdbTestOption3" type="radio" name="rdbTestOptions2" value="rdbTestOption3" /><label for="rdbTestOption3">Test3</label>
   4:  <input id="rdbTestOption4" type="radio" name="rdbTestOptions2" value="rdbTestOption4" /><label for="rdbTestOption4">Test4</label>

You can spot the issue right there, can't you? WebForms won't allow you to have custom-values. It just assigns the same string as in Id to the Value attribute. Now, you can change the value yourself, but I'd really feel like it's hacking. You don't want to mess with good ol' WebForms, now do you? So I had to implement a way for you to map the "fake values" to expected values.

So now you can register these RadioButtons in your Page class like this:"

   1:  Register.RadioButton("Test Options 2").WithValueMappingsOf(
   2:          "1", "rdbTestOption1",
   3:          "2", "rdbTestOption2",
   4:          "3", "rdbTestOption3",
   5:          "4", "rdbTestOption4"
   6:      );

This way you can still use the same WithValueOf construct as in the above item.

Conclusion

Well, I still have to manage the I.See("My Radio Button Name").RadioButton.HasValueOf("some value") construct, and apply the same concept to checkboxes. I'll be blogging about it in the next days.

#139

Posted by heynemann | 0 Comments

Stormwind.Accuracy - Part 3

Introduction

One thing that has been hard to achieve in our acceptance tests is a natural way (fluent) of specifying what data our tables should contain. Usually our scenario is like this:

  1. We have some table that contains some list of entities rendered.
  2. We need to make sure the table has the correct header.
  3. We need to make sure that these entities were correctly rendered.

This has become a large task when it should be quite simple. So, while thinking about it, I talked to my friend Sadek Drobi and he had wonderful ideas on the subject. After a very nice discussion on it, I settled for the following constructs.

Checking Tables Entity-Based

Let's say you have an entity that looks like this:

   1:  public class TestEntity
   2:  {
   3:      private readonly string propertyA;
   4:      private readonly int propertyB;
   5:      private readonly string propertyC;
   6:   
   7:      private TestEntity(string propertyA, int propertyB, string propertyC)
   8:      {
   9:          this.propertyA = propertyA;
  10:          this.propertyB = propertyB;
  11:          this.propertyC = propertyC;
  12:      }
  13:   
  14:      public string PropertyA
  15:      {
  16:          get { return propertyA; }
  17:      }
  18:   
  19:      public int PropertyB
  20:      {
  21:          get { return propertyB; }
  22:      }
  23:   
  24:      public string PropertyC
  25:      {
  26:          get { return propertyC; }
  27:      }
  28:   
  29:      public static IList<TestEntity> GetTestData()
  30:      {
  31:          IList<TestEntity> entities = new List<TestEntity>();
  32:          entities.Add(new TestEntity("a", 1, "d"));
  33:          entities.Add(new TestEntity("b", 2, "e"));
  34:          entities.Add(new TestEntity("c", 3, "f"));
  35:   
  36:          return entities;
  37:      }
  38:  }

Then you have a GridView (I hate them, but I wanted to make sure my approach work with anything that renders a table) like this:

<asp:GridView runat="server" ID="tblTest" AutoGenerateColumns="False">
    <Columns>
        <asp:BoundField DataField="PropertyA" HeaderText="Test table header 1" />
        <asp:BoundField DataField="PropertyB" HeaderText="Test table header 2" />
        <asp:BoundField DataField="PropertyC" HeaderText="Test table header 3" />
    </Columns>
</asp:GridView>

Then in your code-behind file you do this:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      tblTest.DataSource = TestEntity.GetTestData();
   4:      tblTest.DataBind();
   5:  }

So, by now your GridView has rendered a table with all the entities in your list. Now, let's head back to our Acceptance Test. How can I make sure that this page is showing correct data, with minor effort and in a non-fragile way (if I hard-code data here and the data change, I'm in trouble)? Well, that's where Accuracy comes to the rescue! Let's check what that Acceptance Test would look like:

   1:  [Test]
   2:  public void ShouldTestSeeActionInShowEntitiesInTablePage()
   3:  {
   4:      IList<TestEntity> entities = TestEntity.GetTestData();
   5:   
   6:      Story story = Story
   7:                      .AsA("Regular User")
   8:                      .IWantTo("See Action tests")
   9:                      .SoThat("I can test the See action and its sub actions are working");
  10:   
  11:      story.WithScenario("User should see elements in table")
  12:          .Given(I.GoTo("Show Entities In Table Page"))
  13:          .When("The page finishes loading")
  14:          .Then(I.See("Test").Table)
  15:          .And(I.See("Test").Table.WithData(entities));
  16:  }

Hmmm... We're missing something here. How can he know about this table's details? Well, because we told Accuracy that by registering our table like this:

   1:  public class ShowEntitiesInTablePage : Page
   2:  {
   3:      public ShowEntitiesInTablePage()
   4:          : base("/ShowEntitiesInTable.aspx")
   5:      {
   6:          Register.Table("Test")
   7:              .WithHeader("Test table header 1", "Test table header 2", "Test table header 3")
   8:              .WithMapping("PropertyA", "PropertyB", "PropertyC")
   9:              .WithDataStartingInRow(2);
  10:      }
  11:  }

Well, that's pretty much all you need to do to make this work.

Checking a Table Custom-Value Based

Now, let's say you need to check the same table, but you want to check every row yourself, instead of relying in the entity-based mechanism. That's ok, there are cases where you have static tables, and such.

You would just do it like this:

   1:  story.WithScenario("User should see elements in table")
   2:      .Given(I.GoTo("Show Entities In Table Page"))
   3:      .When("The page finishes loading")
   4:      .Then(I.See("Test").Table)
   5:      .And(I.See("Test").Table.As(
   6:          "a", 1, "d",
   7:          "b", 2, "e",
   8:          "c", 3, "f"
   9:      ));

As long as your values in the As() method match the number of columns that you specified in the header when you registered your table, you'll be fine.

Conclusion

If you are feeling adventurous, check the code out. It's commited in Stormwind SVN Trunk at Accuracy Trunk.

There's only one bug yet. The header is not working because Watin does not recognize TH's as TableCells. I'll try to contribute to it, since I found the line of code that should be changed.

If you feel like contributing to Accuracy, just let me know and we can talk it out. Stormwind Project is also in need of new members to the other projects, as well as to help with documentation and portal maintenance. Just check Stormwind Project and see if you feel like helping us out!

#138

Posted by heynemann | 0 Comments

Stormwind.Accuracy - Part 2

Introduction

I've been toying around with the syntax for writing more natural acceptance tests as you can see here. So, while riding the 1h underground home, I was thinking on why I need to register all those components if their names should match (in some way) the key you are using in your acceptance test.

So let's take an example. Say I have a textbox called txtCustomerName. In the way that Accuracy is implemented right now, it can just guess your name from this string: "Customer Name", and in your acceptance test you'd write:

I.Fill("Customer Name").Textbox.With("Some Customer Name")

That does seem more natural than what I had before, and it's exactly what I'm trying to hit with Accuracy (catchy name huh?).

Current State

Right now, my acceptance tests read pretty much the same as they used to, but my DefaultPage class is a lot less cluttered:

   1:  public class DefaultPage : Page
   2:  {
   3:      public DefaultPage() : base("/default.aspx")
   4:      {
   5:          Register.Textbox("My Test Textbox 1");
   6:          Register.Label("My Test");
   7:      }
   8:  }

Note that you only need to Register controls that you want to check with ".And(I.SeeDefaultControls)" syntax.

You can skip control registration altogether if you'd rather check them all yourself like this:

   1:  .And(I.See("My Test Textbox 1").Textbox)
   2:  .And(I.See("My Test").Message)

I am close to a point where you won't even need to have page classes. You'd create only the pages you care about control registration.

As of now I have already implemented the following constructs (each level is a dot):

  • I
    • GoTo("Page Key"); //Updates the current page to be the page with the key and navigate the browser to that URL.
    • Am("Page Key"); //Updates the current page to be the page with the key specified but does nothing to the browser. 
    • SeeDefaultControls; //Tests all controls registered in the current page to check they are visible.
    • See("Element Key")
      • Message; //Tests if the current page contains this text.
      • Button; //Tests if there's a button visible with this key.
        • IsLabeled("button label"); //Tests if there's a button with the given key and with the given label.
      • Textbox; //Tests if there's a textbox visible with this key.
        • ContainsText("text box text"); //Tests if there's a textbox with the given key and that contains the given text.
      • Checkbox; //Tests if there's a checkbox visible with this key.
        • IsLabeled("checkbox label"); //Tests if there's a checkbox with the given key and that a label exists for this checkbox with the given text.
        • IsChecked; //Tests if there's a checkbox with the given key checked.
        • IsNotChecked; //Tests if there's a checkbox with the given key unchecked.
      • Table; //Tests if there's a table visible with this key.
    • Fill
      • Textbox("Textbox Key")
        • WithText("some text"); //Fills the textbox with the given key with the given text.
    • Click("Element Key")
      • Button; //Clicks in the button with the given key.
      • Checkbox; //Clicks in the checkbox with the given key. If the checkbox is checked, unchecks it, otherwise check it.

Conclusion

So, that's the point where you are asking yourself: "Ok, this looks like magic, so where's the trick? How can he get from "Customer Name" to "txtCustomerName"? If it's fixed I don't want to use it! Who uses control prefixes these days, anyway?".

Well, you don't have to like the way I do my own controls :). That's fine. You can just implement your own INamingStrategy resolver and get whatever naming strategy you want. It has just one method to implement, so as long as you follow some convention in naming for your controls (you should anyway!) you'll be fine, whatever the convention is.

Actually, the more I think about it, the more I like it, since this actually forces me to have consistent naming all over the project!

Well, I'll try to churn some more code and get it usable before trying some more advanced scenarios.

Stay tuned to Accuracy news. Check out Claudio Figueiredo's blog (left sidebar) for Validation Everywhere news! He has finished the ValEver integration with Windsor, so if you are using a container and need to validate your method's arguments, that's for you!!!

#137

Posted by heynemann | 0 Comments
Filed under

Stormwind Accuracy

What? Another Stormwind project?! Are you crazy? Are you trying to set some sort of record? Don't you want to finish the ones there first?

I just quoted those imaginary sentences to scare that thought away from me. I like to think that I am an individual with good ideas. So as the ideas come in I try to work them out.

Today I just finished a proof-of-concept of what I think will be a very cool project in the Stormwind umbrella. Stormwind.Accuracy is the name of this new endeavour. I chose this name since I think I missed some targets in the past by not having appropriate acceptance criteria and testing.

I need to give credit where it's due, since a lot of the ideas for Accuracy came from the project I'm currently working in Thoughtworks. I'll disclose the name of the team members if they allow me.

Anyway, on with the show!

Introduction

Are you as tired as me of having to write weird acceptance tests that feel like writing a browser API from scratch in every test? Well, the team I'm currently in was tired as well, so we came up with a way to use NBehave and Watin in order to achieve a sort of BDD Acceptance Testing. It's working so great we have automated acceptance tests for all our stories, even for security (it was hard to do since security is windows integrated, but we got it).

So, as usual, I kept thinking about refactoring that into something easier to write, and above all, semantically readable. After three cycles of writing code, throwing all away and rewriting it, I got to something I really like.

I'll first show what two of my acceptance tests look like, then how I modeled my Pages (more on that in the Pages section) and then discuss some interesting bits of the Accuracy framework.

Acceptance Test Syntax

A sample of an acceptance test syntax:

   1:  [Test]
   2:  public void ShouldTestSeeAction()
   3:  {
   4:      Story story = Story
   5:                      .AsA("Regular User")
   6:                      .IWantTo("See Action tests")
   7:                      .SoThat("I can test the See action and its sub actions are working");
   8:   
   9:      story.WithScenario("User should see textbox")
  10:          .Given(I.GoTo("Default Page"))
  11:          .And(I.SeeDefaultControls)
  12:          .When("The page finishes loading.")
  13:          .Then(I.See("My Test").Message);
  14:  }

The test output for that test is:

Story:
  As a Regular User
  I want to See Action tests
  so that I can test the See action and its sub actions are working

  Scenario 1: User should see textbox
  Narrative:
    Given That
      I navigate to Default Page at /default.aspx
      and that I see the default controls for the Default Page
    When
      The page finishes loading.
    Then
      I see the "My Test" message.

Another sample:

   1:  [Test]
   2:  public void ShouldTestFillAction()
   3:  {
   4:      string testTextBox1Text = "My Custom Special Text";
   5:   
   6:      Story story = Story
   7:                      .AsA("Regular User")
   8:                      .IWantTo("Fill Action tests")
   9:                      .SoThat("I can test the Fill action and its sub actions are working");
  10:   
  11:      story.WithScenario("User should fill textbox with text")
  12:          .Given(I.GoTo("Default Page"))
  13:          .When(I.Fill.TextBox("Test Textbox 1").With(testTextBox1Text))
  14:          .Then(I.See("Test Textbox 1").TextBox.ContainsText(testTextBox1Text));
  15:  }

The test output for this test is:

Story:
  As a Regular User
  I want to Fill Action tests
  so that I can test the Fill action and its sub actions are working

  Scenario 1: User should fill textbox with text
  Narrative:
    Given That
      I navigate to Default Page at /default.aspx
    When
      I fill the Test Textbox 1 with "My Custom Special Text".
    Then
      I see that the Test Textbox 1 textbox contains the "My Custom Special Text" text

Page Modeling

The page model is how you abstract pages for your tests. The current way of implementing that page model is to create classes that inherit from Page (a class in Accuracy) and initializing them in Accuracy (more on that in another post).

A page class looks like this:

   1:  public class DefaultPage : Page
   2:  {
   3:      public DefaultPage() : base("Default Page", "/default.aspx")
   4:      {
   5:      }
   6:      protected override void RegisterPageComponents()
   7:      {
   8:          Register.Label("My Test").WithText("My Test");
   9:          Register.TextBox("Test Textbox 1").WithId("txtTest1");
  10:      }
  11:  }

As you can see, we register components for this page with keys, which are in turn used in our tests for easy reference of page components. The page also passes an URL and a Key for itself as a way of automating navigation.

Interesting Bits of the Framework so far...

Well, so far I really like the clear style of writing acceptance tests. I also am very fond of the output I get from the tests. Even so, there are three parts of the framework right now that go unnoticed in the above code.

The first one is the concept of a Context in the acceptance tests. So you get a singleton with some nice information on the current run, like current page, if the framework is initialized, a list of available pages and stuff like that. It's really helpful when you need to extract information on the currently running test.

The second one is the security part of the framework. If you were really paying attention to the code above you have seen this code: .AsA("Regular User"). Whenever you execute a .AsA directive in Accuracy, an event is raised in the Current Context (see above paragraph) with this security information. You would ask me why is that, right? What do you care about this stuff? Well, you would usually need to se some security information for each of your acceptance tests, providing you have authentication in place and some sort of role-based authorization. So, Accuracy allows you to implement your own security handler, and as long as you subscribe to the correct event, whenever an .AsA directive is executed your code will be executed, so you get to take direct action (change a config file, update the database, or whatever you have to do).

The third one is the Action model currently in place in Accuracy. It's really easy to implement new actions like TextBoxExistsAction or ClickLinkAction, for instance. Hopefully I'll get to implement a lot of that till the first release of Accuracy.

As a last interesting thing of the framework is that we're not coupled with Watin. We currently use it to drive our tests, but we use it through an IBrowserDriver interface. This way, we can implement other Browser Drivers later if need be.

Feedback?

I know that you can't really test drive the code right now, but I hope that all of that gave a feel of what it looks like. I really want feedback on the syntax of stuff, because that's the thing I am most concerned about right now. Acceptance tests should convey the criteria in a meaningful way, and they really should be easy to read.

If you want to help me out here, please DO! Just add your comment here!

#136

Priority vs Effort Evaluation

This morning I am evaluating the next steps I have for Stormwind. There are so many that I am confused as to which ones should I start. So I had t come up with a straightforward way of deciding that.

First I had to find out what activities I had to do. So I wrote the following list (it's exactly as I wrote!):

  1. DeployIt
  2. Code Churn CCNet Plug-in
  3. NMVP 1.0.0 (DDD?)
  4. ValEver Windsor Interceptor
  5. Symian (NAnt)
  6. License Verifier
  7. Cache
  8. Digital Fortress
  9. Migrations
  10. Outliner
  11. Portal Documentation

Cool, I found out what I have to do in the next 3 years, lol!

Now I must find what to do first! Then I thought: "Well I'll rank those in priority, 1 being higher priority, and I'll score each an effort rating from 1 to 10, with 10 being a very hard task or a very big task.".

So here's the new List:

Task Priority Effort
DeployIt 6 6
Code Churn 10 10
NMVP 1.0.0 (DDD?) 1 10
ValEver Windsor Interceptor 7 3
Symian (NAnt) 9 4
License Verifier 5 3
Cache 2 5
Digital Fortress 4 7
Migrations 8 4
Outliner 3 9
Portal Documentation 11 10

I'm sure you all know that those are arbitrary numbers assigned based on what I think the priority and efforts are for each of those tasks.

Ok, so now what should be my next task. I just multiplied the priority and the complexity based on the principle that the higher priority and smaller tasks should be done first.

I got the following result:

10 - NMVP 1.0.0 (DDD?)
10 - Cache
15 - License Verifier
21 - Valever Windsor Interceptor
27 - Outliner
28 - Digital Fortress
32 - Migrations
36 - Symian (NAnt)
36 - DeployIt
100 - Code Churn Plug-in
110 - Portal Documentation

Now, this was a very interesting result. I really thought I should do the Code Churn Plug-in asap, but after this experiment, I started to think that it's not as important as those other tasks, as it won't add as much value to the community as the other ones do. I'm prioritizing tasks that will help in other tasks (like NMVP, ValEver and Cache will all help in DeployIt).

What do you guys think of my method? Is there a better way of prioritizing? The upper side of this experiment is that it made me think of what I had to do and prioritize it!

Now back to waiting VS 2005 download!

#135
 

Posted by heynemann | 5 Comments

Stormwind Project - I'll be right back

I know that Stormwind Project is lacking activity on my account, and I hope to remedy this as soon as possible.

As soon as I get my home broadband I have some stuff to throw at you guys!

Keep posted!!!

#134
 

Posted by heynemann | 0 Comments

My First Day at Thoughtworks

Well, to sum it up: WOW! I couldn’t be more impressed. I’m not impressed by how good people were technically. I’m impressed by how nice everyone is. I never got such a positive vibe from people working with me.

When I first arrived here I was waiting in the “kitchen”, since Danilo that started in the same day as me would only arrive in half an hour. You can tell that TW is not just your regular company by their kitchen. It has all sorts of things to make you feel home, like sodas, chocolates, fruits, videogames, board games and cushions. Well I can say it works. I actually feel home.

So I waited until he got here. When he arrived we were introduced to all sorts of financial stuff we needed to know about TW. Vacation, payroll details and stuff like that.

After that we had a meeting with the People People (this is not a typo). They told us all about how the company is structured, what is not tolerated here (like racism and harassment, which is REALLY nice), what to expect from TW and what they expect of us. It was a really nice talk.

We then had our meeting with the Resource Management people. They are the ones that tell us which projects we’ll be in. I already have a brand new .Net project awaiting me next Monday. Danilo is in a Ruby project himself (lucky you man!!!). I’m REALLY anxious for starting to work and code! Those of you that know me can tell how much I like coding!

Then we went for the sweetest meeting of the day. Don’t get me wrong, people in the other meetings were as nice as it gets, but in this meeting I got my brand new MacBook Pro! It’s really beautiful and I’m now learning all sorts of things about Mac OS X Leopard. It’s a brand new world to explore! Isn’t it exciting???

Well, the infrastructure people explained to us all about how to use e-mail, calendars, timesheet apps and stuff like that. Again, a really nice talk.

Since this last one took longer than the others, we called it a day and went home.

I’m really looking forward starting in a real project! Wish me LUCK!

#133 

Posted by heynemann | 5 Comments

UK so far…

Well, this most definitely is going to be a long post, so if you’re only interested in my first day at Thoughtworks, skip to my next post. THIS IS NOT A TECHNICAL POST!

Arriving at the UK

Once we (me and my wife Aline) arrived here in Heathrow airport and I showed her around the airport she just loved it. Too bad it didn’t look so fancy after 4 hours waiting for our transport.

Let me explain that. It was not our transport’s fault. It was really our letting agent’s fault. We arrived in Heathrow at 7:45 AM. I asked the agent if he could be in the apartment to give us the keys at 10-11 AM. He replied that he would only be available after 1:00 PM, so what were we supposed to do? We just waited for him at the airport and scheduled our transport to 11:45 AM. We arrived at our apartment precisely at 1:15 PM (I know it’s a long run, but Heathrow is far west and Barking is far east).

When we arrived: SURPRISE! No letting agent for us. So we phoned him and he said he’d be with us in around 15 minutes. What followed was a mix of lies and confusion, as the agent and his manager kept telling us that they would be with us in minutes and never showing.

We stood in the street with 6 pieces of luggage for 6 HOURS! That’s right! 6 HOURS!!! My wife was very upset when I decided I had to take a cab to the letting agency and sort things out.

So I left my wife alone, in a foreign country, with 6 pieces of luggage, in the street, AT NIGHT! I believe you can imagine how I felt, right?

After a LONG ride (the letting agency couldn’t be near, now could it?), I arrived at the agency. The manager proved to be a real jerk telling me that it’s really my fault that I went to the apartment instead of showing in the letting agency. I then had to sign the contract without reading it (I know it sounds crazy, but remember my wife ALONE?), and to make things even worst, HE GAVE ME THE WRONG KEYS!!!!

We had to ask our REALLY nice neighbours from downstairs to help us get inside the building. And then at about 7:30 PM we got to our apartment. This was really the worst day of my life so far.

UK Services

Now this is amusing. We always make jokes about the Telecom companies there in Brazil, but British Telecom does not make me want to laugh, it makes me want to cry. 20 days to install a landline??? Is it just me or is that just ridiculous? Well, I’ve been here for more than a week now and I still couldn’t book a BT landline installation.

Wanna know why? Because I don’t have a banking account here. Oh, you got that right. Want to use an international credit card? I don’t think so. Only UK-issued ones. So my advice to anyone coming to the UK is: GET A BANKING ACCOUNT ASAP!

My Citibank account should be up and running in the next couple days (BIG KUDOS for Thoughtworks for it), and then we’ll be able to have broadband, which brings me to a huge APOLOGY to you readers for not writing more here, but it’s been a really rough period for me, with a lot changing in my life.

Nice Stuff

Not everything’s gone bad though. We visited several nice places.

We had a really lovely afternoon at the British Museum, where we saw a LOT of mankind history become alive.

We had a very nice time visiting Harrods, which is one freaking huge department store. I really advise anyone visiting it, not to miss a visit to the Patisserie Valerie, which is just around the corner. They have the most delicious tarts I’ve ever had.

Seeing all of London, including a panoramic view of the Big Ben and the Houses of Parliament, in the London Eye is an amazing experience. We just loved it. After riding the wheel we took a walk to the Big Ben. It’s really near and it’s very nice to cross the Thames River walking in one of the bridges.

I’m sure that there’s a lot to see yet, and we are really looking forward. We’re planning a trip (probably to Paris) this year as well.

Conclusion

Well, now things are most sorted out, since we got everything we need (for now at least) in the apartment. We got a really nice 32’’ LCD TV, SKY is installed (not activated yet, but installed at least).

We got a phone card that we can talk to Brazil in a kind of cheap way (CRAZY TO USE VOIP though). So talking to our parents and family sort of makes it a little easier.

So if you’re coming to the UK and you need logistics help (I could’ve used it!!!), don’t hesitate to e-mail me at heynemann at gmail dot com.

#132 

Posted by heynemann | 0 Comments

KickAssVPS

Once more KickAssVPS has proven to be a REALLY engaged sponsor for Stormwind Project.

We installed Mingle yesterday (more about it in another post) in our build server, so we can use it for management of our projects.

The thing is that Mingle is a little heavy on the RAM side of things. So our VPS with 480mb couldn´t endure having both CruiseControl and Mingle together at the same time.

We thought of giving up, but before doing so, I thought of giving a try at asking KickAssVPS for a little more RAM to our server. They didn´t just give us a little more Ram. They gave us 1GB RAM! That is freaking AWESOME!

So, now we have our Mingle Server up and running. I´ll ask the guys at work (It´s so COOL TO SAY THAT) for an unlimited license for Stormwind Project.

#131

Posted by heynemann | 0 Comments

I´m a ThoughtWorker

I am officially a ThoughtWorker now! I was in London (as you might´ve noticed from previous posts) and I did a full-day interview with them for a developer job in Thoughtworks UK.

Working with ThoughtWorks was a dream of mine ever since I learnt about the company philosophy. I really dig agile development and I just love learning new stuff. I am sure this is a bold move and one that I´m not only ready to take, but actually anxious.

Several of my friends already know about it and are holding their breath to blog about it! Ok, guys, you´re good to go.

The reason you´re good to go is that my current employers (Perlink Consulting) were AWESOME! They were very happy for me and were very supportive. I didn´t expect any less of them. I had a GREAT time here and I would surely recomend working here for anyone in Rio de Janeiro (and probably São Paulo in a very near future). If I´m going to Thoughtworks today, I owe it to them.

I am very excited about working in ThoughtWorks. I have the perspective of LEARNING a lot in the near future. I´m very excited about the Immersion training, about working in a very agile environment, about living in London, ... Yes, you got that right! I am excited on everything!

I´ll be leaving for London in early February with my wife. She´s also very excited on moving to the UK. I am sure we´ll both learn a lot about work and life. I couldn´t endure all the life-changing without her and all the love and care she devotes me! She is my supporting pillar!

Last but not least, I´d like to thank all my friends and family who were all cheering for me and got REALLY happy for me after the news. You know who you are and I love you all!

Well...TW UK... Here I come!

#130

Updates:

Claudio Figueiredo posted about me here. Thanks a lot man for the kind words!

willeke also posted about me here. Thanks mate! Really nice words!

Paulo Quicoli posted about me here (portuguese). Thanks for the nice words buddy!

Posted by heynemann | 5 Comments

Trivia Answers and CCNet Build Breaking Changes plugin release

Well, I know that you wanna know the answers... Ok, I'll say it, just let me show a very nice place here in London first!

 

A very old building. The mayor started repairing it so it won't be a Build Breaking! Ok, I admit that was awful, lol.  

Let's get the Trivia out of our minds!!!

Answers

First Question

Well, it's hard to answer it exactly, but we'll try. Yes, as you guessed there are two from TestMethod and TestMethod2. Wait, it doesn't stop here. There are two more: one for getting TestProperty and one for setting it. I bet you knew this one too. Well, .Net creates under the covers a method called get_PropertyName and a set_PropertyName that it uses to provider property functionality.

Cool, the answer is FOUR then, right? NO!

The problem is that .Net creates more stuff behind the covers. For EVENTS!

It creates one method for adding a handler to an event, and another for removing. So two more! Keep counting. There's more!

It creates as well one method for Raising the event (check msdn documentation).

And it keeps track of an array of methods that might have been associated with the event in the IL (check msdn documentation).

So if you were keeping track, and assuming that the last two are optional, we have AT LEAST 6 methods. Just know that this might be far from the reality and there might be more methods.

Second Question

This one's easy. Assuming that the root namespace is Root, we should pass Root.TestClass.TestEnum, right?

WRONG! The correct string is Root.TestClass+TestEnum, since TestEnum is a nested entity, and all nested entities are signaled with a + sign.

The same is valid for the other two classes which would be Root.TestClass+MyNestedClass and Root.TestClass+MyNestedClass+MyTwofoldNestedClass.

Third Question

Well, let's see... This property should return true for all three, since they are all public, right? Not really my friend. Here enters the obscure IsNestedPublic property. When a type is nested it's IsPublic property ALWAYS evaluates to false, and you should instead use the IsNested property in combination with the IsNestedPublic one. 

Fourth Question

Well, at first everything will go smooth, right? But in the end the struct list will contain two types: the enumeration and the struct. WOOOT??? Well, since .net enumerations ARE value types as well there's nothing actually wrong with that. To fix it just add a continue; statement after each list addition. This way you'll get the values right.


How many did you score? 

CCNet Build Breaking Changes plugin

 This is what the report looks like today (you can check it online at http://buildserver.stormwindproject.org):


This report contains a lot of information.

First it tells if my build contains breaking changes with a very visible notice at the top (this notice also shows in the build summary to let the user know that the build contains breaking changes.

Second it details ALL changes so you can decide on what's important to track or not. This way you always know if some break in the public contract of a given assembly will alter the functionalities of the users of that assembly.

The process of setting this up in your own Build Server is detailed in the Getting Started page in Stormwind Project portal. Check it out! You can download it here.

We want feedback as to what you'd like to see included in the plug-in.

See yall! 

#129 

Posted by heynemann | 0 Comments

Reflections on Reflection

Hey all!
This is me posting from the beautiful city of London, UK!

So far 55 pictures, but that's not what I wanted to talk about (but my next posts will all come with a London pic, that's how much I like this city).

The beautiful streets around King's Cross St. Pancras station.
 

I've did some pretty wicked stuff with reflection in the course of my .Net career, both in .Net 1.1 and 2.0. I've built an ORM heavily based in reflection, I did NMVP that uses it as well as I did a Mocking engine specialized in mocking views for NMVP.

After finishing the Build Breaking Changes plug-in (next post) I found out that I didn't know as much reflection as I thought. But instead of telling you, I'll let you try to score.

Reflection Trivia

First question

If I have a class with the following code:

   1:  public class TestClass{
   2:    public string TestProperty{
   3:      get{
   4:        //return some stuff.
   5:      }