Sunday, March 07, 2010

I have previously blogged about some new features in MSBuild 4.0 at:

Besides inline tasks there are a set of other new features including Property Functions. In this post we will discuss property functions and how you might use them in your build scripts. With property functions you can call an instance method of the string object on properties now.

The syntax will be in the format $(PropertyName.MethodName([Parameters])) when you want to invoke a string method. Parameters in the previous expression is optional. For instance if you need to call the Trim method then you do not need to supply any arguments. Take a look at the snippet below to get a better feel for how to use these new features.

<Project ToolsVersion="4.0" 
DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <SampleString>This is a sample string</SampleString> <SampleString2> This is a sample string </SampleString2> <!-- Here we now can call instance methods on the String class --> <Sub04>$(SampleString.Substring(0,4))</Sub04> <Contains01>$(SampleString.Contains("This"))</Contains01> <Contains02>$(SampleString.Contains("this"))</Contains02> <CompareTo01>$(SampleString.CompareTo($(SampleString)))</CompareTo01> <EndsWith01>$(SampleString.CompareTo("string"))</EndsWith01> <Insert01>$(SampleString.Insert(2,"INSERTED"))</Insert01> <Trim01>$(SampleString2.Trim())</Trim01> </PropertyGroup> <Target Name="Demo"> <Message Text="SampleString: $(SampleString)" Importance="high"/> <Message Text="Sub04: $(Sub04)" Importance="high"/> <Message Text="Contains01: $(Contains01)" Importance="high"/> <Message Text="Contains02: $(Contains02)" Importance="high"/> <Message Text="CompareTo01: $(CompareTo01)" Importance="high"/> <Message Text="EndsWith01: $(EndsWith01)" Importance="high"/> <Message Text="Insert01: $(Insert01)" Importance="high"/> <Message Text="Trim01: $(Trim01)" Importance="high"/> </Target> </Project>

In this snippet I am calling various string methods on the properties defined. The results of executing this are shown in the fragment below.

Demo:
  SampleString: This is a sample string
  Sub04: This
  Contains01: True
  Contains02: False
  CompareTo01: 0
  EndsWith01: 1
  Insert01: ThINSERTEDis is a sample string
  Trim01: This is a sample string

This is just one way that you can use property functions. We can also call a static methods (and properties) on a known set of classes. See http://msdn.microsoft.com/en-us/library/dd633440%28VS.100%29.aspx for the list of complete classes that you can call static methods on. The syntax is as follows $([Full-Class-Name]::Method(Parameters)) or if you are calling a property you just leave off the (Parameters). To demonstrate this I have created the following file.

<Project 
    ToolsVersion="4.0" 
    DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <!-- 
      Here we Now01 can call static methods/properties on many types 
      See http://msdn.microsoft.com/en-us/library/dd633440%28VS.100%29.aspx
      for the list of classes that we can call static methods/properties on.
    -->
    <Now01>$([System.DateTime]::Now)</Now01>
    <Pow01>$([System.Math]::Pow(2,3))</Pow01>
    <TempFile01>$([System.IO.Path]::GetTempFileName())</TempFile01>
  </PropertyGroup>
  
  <Target Name="Demo">
    <Message Text="Now01: $(Now01)" Importance="high"/>
    <Message Text="Pow01: $(Pow01)" Importance="high"/>
    <Message Text="TempFile01: $(TempFile01)" Importance="high"/>
  </Target>

</Project>

And the result is:

Demo:
  Now01: 3/6/2010 7:31:23 PM
  Pow01: 8
  TempFile01: C:\Users\Ibrahim\AppData\Local\Temp\tmp4C1.tmp

Similar to this you can call a handful of MSBuild methods. Those methods are documented at http://msdn.microsoft.com/en-us/library/dd633440%28VS.100%29.aspx. You would use a similar syntax to access those which is $([MSBuild]::Method(Parameters)). To show you those take a look at the follwing sample file.

<Project 
  ToolsVersion="4.0" 
  DefaultTargets="Demo" 
  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <Add>$([MSBuild]::Add(5,9))</Add>
    <Subtract01>$([MSBuild]::Subtract(90,768))</Subtract01>
    <Mult01>$([MSBuild]::Multiply(4,9))</Mult01>
    <Div01>$([MSBuild]::Divide(100,5.2))</Div01>
  </PropertyGroup>
  
  <Target Name="Demo">
    <Message Text="Add: $(Add)" Importance="high"/>
    <Message Text="Subtract01: $(Subtract01)" Importance="high"/>
    <Message Text="Mult01: $(Mult01)" Importance="high"/>
    <Message Text="Div01: $(Div01)" Importance="high"/>
  </Target>

</Project>

I will leave it up to you to execute that file to see the result, but you can probably figure it out :)

Sayed Ibrahim Hashimi

Sunday, March 07, 2010 12:35:29 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Thursday, February 25, 2010

This weekend I will be speaking at the South Florida Code Camp. This has historically been a very popular event (>500 people) with a lot of good speakers.

I will be presenting 2 topics there, the abstracts are below.

MSBuild 4.0 What’s New

MSBuild, the Microsoft Build Engine, was first introduced with Visual Studio 2005. This was MSBuild 2.0, and it was delivered along with the .NET Framework 2.0. The next major release of MSBuild, version 3.5, was introduced for Visual Studio 2008 and was deployed with the .NET Framework 3.5. Now the third major version, 4.0, is being introduced with Visual Studio 2010, and in concert with previous releases is being shipped with the .NET Framework 4.0. In this session we will talk about the new features included with MSBuild 4.0 and how it can make your MSBuild files better. The topics we will talk about will include.
•    Inline Tasks
•    Property Functions
•    Item Functions
•    Before / After Targets
•    Support for C++ projects (both native and managed)
•    New Object Model

Simplifying deployments with MSDeploy and Visual Studio 2010

In this session we will demonstrate how to greatly simplify deployments of web applications using MSDeploy. MSDeploy is shipped with Visual Studio 2010 and is available as a separate download. Visual Studio 2010 has enhances support for MSDeploy and we will go over many of those details in this session. We will also be discussing how MSDeploy can be used as a stand alone tool outside of Visual Studio 2010. So if you are not able to upgrade to Visual Studio 2010 but developing web applications this is still a great for you.

If you are in the South Florida area this is definitely an event that you don’t want to miss out. Please stop by and see me!

Sayed Ibrahim Hashimi

Thursday, February 25, 2010 4:01:47 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Tuesday, February 09, 2010

If you are an MSDN subscriber you can now download Visual Studio 2010 Release Candidate as well as the TFS 2010 Release Candidate. You can read Brian Hurry's post about the release. Here are some key dates, if you are an MSDN subscriber you can get it now, and if not then you will have to wait until Feb 10. Still no word on when the RTM will ship, but hopefully it will be soon so that more organizations will begin adopting it and we can leave VS 2008 in the dust. Since the Visual Studio 2010 Launch is on April 12, 2010 it should be just around the corner. You should be aware that the launch date doesn't always equal the release date. Launch date is set by marketing to start the launch events, but the RTM date can vary, but will typically be in that same ball park.

Sayed Ibrahim Hashimi

Tuesday, February 09, 2010 3:44:10 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Friday, January 22, 2010

This post contains based on .NET 4.0 Beta 2 and Visual Studio 2010 Beta 2 which may change.

The other day I wrote my first post on Inline Tasks in MSBuild 4.0, this post will add onto that topic. In the previous post we covered some basics, but there were a lot that was skipped. Last time we demonstrated how to pass parameters but we never declared what type those parameters were. If you declare a parameter and leave off the type, then it will be declared as a string. If you need to declare parameters of other types then you need to use the ParameterType attribute on the parameter. You have to pass in the full name of the type to be used. For example if you need to declare an int you must use System.Int32, not int and not Int32 but System.Int32. It would be good if they supported aliases like int, string, long, etc but right now they don't. Below you'll find a new inline task which can be used to perform a substring. I've placed this in a file named IT-Substring-01.proj.

<!--

Sample Demonstrates Inline Tasks

© 2010 Sayed Ibrahim Hashimi

-->

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask

    TaskName="Substring"

    TaskFactory="CodeTaskFactory"

    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >

    <ParameterGroup>

      <Input Required="true" />

      <StartIndex Required="true" ParameterType="System.Int32" />

      <Length ParameterType="System.Int32" />

      <Result Output="true" />

    </ParameterGroup>

    <Task>

      <Code Type="Fragment" Language="cs">

        <![CDATA[

        if (Length > 0)

        {

            Result = Input.Substring(StartIndex, Length);

        }

        else

        {

            Result = Input.Substring(StartIndex);

        }

        ]]>

      </Code>

    </Task>

  </UsingTask>

 

  <Target Name="Demo">

    <Substring StartIndex="8" Input="Demo of Inline Tasks">

      <Output PropertyName="taskValue" TaskParameter="Result"/>

    </Substring>

    <Message Text="Value from task: $(taskValue)" />

   

    <Substring StartIndex="0" Length="4" Input="Demo of Inline Tasks">

      <Output PropertyName="taskValue" TaskParameter="Result"/>

    </Substring>

    <Message Text="Value from task: $(taskValue)" />

   

  </Target>

</Project>

In the task above I have declared 4 parameters, from those two have the type specified to be int. If we execute the Demo target here is the result.

From the above image you can see that the task performs the actions requested. One thing to make a mental note of above is my usage of a CDATA tag to wrap the definition of the task. I would suggest that you do so for all inline tasks that you write.

The types supported for parameters on inline types are the same for normal types. For a detailed account of that see my book, but as a general guideline it accepts string, primitive types, ITaskItem, and arrays of all three.

Let's see how we can use an array in an inline task. I created a simple task which will create a list of Guids and place them into an array and return the result back to the calling MSBuild script, the file I placed this is in named IT-CreateGuid-02.proj. The contents of that file are shown in the snippet below.

<!--

Sample Demonstrates Inline Tasks

© 2010 Sayed Ibrahim Hashimi

-->

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask

    TaskName="CreateGuid02"

    TaskFactory="CodeTaskFactory"

    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >

    <ParameterGroup>

      <NumToCreate ParameterType="System.Int32" Required="true" />

      <Guids ParameterType="System.String[]" Output="true" />

    </ParameterGroup>

    <Task>

      <Code Type="Fragment" Language="cs">

        <![CDATA[

            List<string> guids = new List<string>();

            for (int i = 0; i < NumToCreate; i++)

            {

                guids.Add(Guid.NewGuid().ToString());

            }

            Guids = guids.ToArray();

        ]]>

      </Code>

    </Task>

  </UsingTask>

 

  <Target Name="Demo">

    <CreateGuid02 NumToCreate="1">

      <Output ItemName="Id01" TaskParameter="Guids" />

    </CreateGuid02>

    <Message Text="Id01: @(Id01)" Importance="high" />

 

    <CreateGuid02 NumToCreate="4">

      <Output ItemName="Id02" TaskParameter="Guids" />

    </CreateGuid02>

    <Message Text=" " Importance="high" />

    <Message Text="Id02: @(Id02)" Importance="high" />

  </Target>

 

</Project>

Above you can see that I declared the parameter Guids as System.String[]. I typically prefer to use generic lists instead of arrays so in my task definitions I will use a list and then just call ToArray when I assign the output parameter. Here is a nifty, but very simplistic task. Given an item list, it will filter them based on a Regular Expression passed in.

<!--

Sample Demonstrates Inline Tasks

© 2010 Sayed Ibrahim Hashimi

-->

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask

    TaskName="FilterList"

    TaskFactory="CodeTaskFactory"

    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >

    <ParameterGroup>

      <ListToFilter ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />

      <Filter Required="true" />

      <FilteredList ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />

    </ParameterGroup>

    <Task>

      <Using Namespace="System.Text.RegularExpressions" />

      <Code Type="Fragment" Language="cs">

        <![CDATA[

            var results = (from l in ListToFilter

                           where Regex.IsMatch(l.ItemSpec, Filter)

                           select l).ToList();

 

            FilteredList = results.ToArray();

        ]]>

      </Code>

    </Task>

  </UsingTask>

 

  <ItemGroup>

    <Source Include="src\01.cs" />

    <Source Include="src\02.cs" />

    <Source Include="test\test01.cs" />

    <Source Include="test\sub\test02.cs" />

    <Source Include="test\sub\test03.cs" />

    <Source Include="test\sub\sub2\test04.cs" />

  </ItemGroup>

 

  <Target Name="Demo">

    <FilterList ListToFilter="@(Source)" Filter="test">

      <Output ItemName="_filteredList" TaskParameter="FilteredList" />

    </FilterList>

    <Message Text="Filter: test. Results: @(_filteredList)" />

   

    <!-- Clear the list before calling again -->

    <ItemGroup>

      <_filteredList Remove="@(_filteredList)" />

    </ItemGroup>

 

    <Message Text="======" />

    <FilterList ListToFilter="@(Source)" Filter="sub\\">

      <Output ItemName="_filteredList" TaskParameter="FilteredList" />

    </FilterList>

    <Message Text="Filter: .\sub. Results: @(_filteredList)" />

  </Target>

</Project>

Here you see that you can you can perform LINQ queries inside of inline tasks without any additional setup. Here is the result of executing the Demo target on this script.

Another thing to notice is the Using element under the Task element. This injects a Using statement into the generated class for the given namespace. If you need to reference another assembly you can do this with the Reference element under the Task element.

 

Sayed Ibrahim Hashimi

Friday, January 22, 2010 4:01:46 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Wednesday, January 20, 2010

This post contains based on .NET 4.0 Beta 2 and Visual Studio 2010 Beta 2 which may change.

If you didn't already know, MSBuild will have a new version shipped with .NET 4.0 (Visual Studio 2010 will use this new version). I will cover many of those features here. This is the first in a series of posts that I will make regarding MSBuild 4.0. One of the big additions to MSBuild 4.0 is Inline Tasks. I'm pretty excited about this new addition. The story before was if you wanted to perform any action it was always through a Task. Which worked pretty well, but the major drawback is that the tasks needed to be written in code and then compiled into an assembly in order for it to be used. What this meant was if you wanted to perform an action (however simple) that wasn't covered out of the box you would have to look for 3rd party tasks or write one yourself. This is time consuming and can be tricky from a "deployment" perspective. Now with Inline Tasks you can declare the behavior of the task right inside of the MSBuild file itself.

Inline Task

The way that Inline Tasks are supported is by using the UsingTask XML element. This element was around before but it has some new options. If you read my book, you probably saw a few different Hello World tasks that I created. In order to demonstrate Inline Tasks I have taken a similar set of examples. Take a look at the project file (IT-HelloWorld-01.proj) below.

<!--

Sample Demonstrates Inline Tasks

© 2010 Sayed Ibrahim Hashimi

-->

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask

    TaskName="HelloWorld"

    TaskFactory="CodeTaskFactory"

    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >

    <Task>

      <Code Type="Fragment" Language="cs">

        Log.LogMessage("Hello World!");

      </Code>

    </Task>

  </UsingTask>

 

  <Target Name="Demo">

    <HelloWorld />

  </Target>

 

</Project>

For this basic inline task here are the key things to note, the name of the task is specified in the TaskName attribute. You will use this like you would any other task inside of targets. The definition of the task will be contained in the Code XML element. In order to call that task, I use the syntax <HelloWorld /> inside of the Demo target. The same exact way "classic" tasks are called. Here is the result.

The result shown above is as expected.

Inline Task with Parameters

You can also make inline tasks with parameters, both required and optional. Here is an example (IT-HelloWorld-02.proj) with a lone required parameter.

<!--

Sample Demonstrates Inline Tasks

© 2010 Sayed Ibrahim Hashimi

-->

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask

    TaskName="HelloWorld"

    TaskFactory="CodeTaskFactory"

    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >

    <ParameterGroup>

      <Name Required="true"/>

    </ParameterGroup>

    <Task>

      <Code Type="Fragment" Language="cs">

        Log.LogMessage(string.Format("Hello {0}",Name));

      </Code>

    </Task>

  </UsingTask>

 

  <PropertyGroup>

    <YourName Condition=" '$(YourName)'=='' ">Sayed</YourName>

  </PropertyGroup>

 

  <Target Name="Demo">

    <HelloWorld Name="$(YourName)" />

  </Target>

 

  <Target Name="DemoWithNoName">

    <!-- This shows the result if you don't pass in a required param -->

    <HelloWorld />

  </Target>

 

</Project>

If you take a look at the UsingTask declaration above you will see that I included a ParameterGroup element. All parameters must be included under that element. In this case we just have one. If we execute the Demo target the result will be as follows.

We can see that the message was sent to the console as we expected. You can execute the DemoWithNoName if you are interested in verifying that MSBuild will ensure that required parameters are set.

Inline Tasks with Output Parameter

You can also create your own inline tasks which have one or more output parameters. You will define those output parameters under the ParameterGroup element and use the Output="true" attribute. Take a look at IT-HelloWorld-03.proj below.

<!--

Sample Demonstrates Inline Tasks

© 2010 Sayed Ibrahim Hashimi

-->

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask

    TaskName="HelloWorld"

    TaskFactory="CodeTaskFactory"

    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >

    <ParameterGroup>

      <Name Required="true"/>

      <TaskMessage Output="true"/>

    </ParameterGroup>

    <Task>

      <Code Type="Fragment" Language="cs">

        TaskMessage = string.Format("Hello {0}",Name);

        Log.LogMessage(TaskMessage);

      </Code>

    </Task>

  </UsingTask>

 

  <PropertyGroup>

    <YourName Condition=" '$(YourName)'=='' ">Sayed</YourName>

  </PropertyGroup>

 

  <Target Name="Demo">

    <HelloWorld Name="$(YourName)">

      <Output PropertyName="MsgFromTask" TaskParameter="TaskMessage"/>

    </HelloWorld>

    <Message Text="Message from task: $(MsgFromTask)" Importance="high" />

  </Target>

 

</Project>

In this example I created a HelloWorld task to output the entire message back to the calling MSBuild task invocation inside the target. This output parameter is the TaskMessage parameter. Inside the Demo target I call the task and then print the value that was passed back from the task. Here is the result of that.

From here we can see that the value was correctly sent back to the script.

 

There is a lot more to inline tasks and I plan on covering more features very soon here, but this should get you started.

 

Sayed Ibrahim Hashimi

Wednesday, January 20, 2010 10:31:12 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Wednesday, December 09, 2009

Unit testing has been around for quite a while and a lot of developers have created their own unit tests. Even being a simple concept and having been around for some time I still think that unit tests are misunderstood, poorly written and don't follow best practices by a majority of developers. I'm not a unit testing expert but there are some guidelines that I try to follow when I create unit tests some of those are listed below (in no particular order).

  • Make them small
  • Make them self contained
  • Make the names describe what the test case tests (at the price of a long name)
  • Follow the arrange/act/assert pattern, i.e. don't do something like arrange/act/assert/act/assert, etc.
  • Don't make database calls!
  • Use mocks when necessary to ensure that you test the correct piece of code
  • Consider making methods/properties to be internal instead of private. You can use the InternalsVisibleTo attribute to allow testing of internal items.
  • Don't have app.config for your unit tests. Unit test should "arrange" the configuration in code.

If you make your unit tests too long and to test more than one item then they will become a pain to maintain, which leads to them being ignored and eventually to a complete breakdown to your testing effort in general.

I have recently been thinking more about how unit tests are being used throughout software development. Also I've been reading ASP.NET MVC in Action which coincidently puts a lot of emphasis on unit testing. I found a few quotes in Chapter 3 of that book, which covers Controllers, and thought that I would share them here because I agree with statements whole heartedly. Text in italics are my own comments.

  • Unit tests run fast because they do not call out of process (i.e. no database calls, no web service calls, etc)
  • It is very difficult to test poorly designed code. (Do you ever have a set of code and think to yourself, "I can't write unit tests for this, it's impossible", at this point you should consider to refactor it because this is a red flag for bad code!)
  • (While discussing mocking)… unit testing becomes easy and soon becomes a repetitive pattern of faking dependencies and writing assertions. Over time, if you employ this technique, you will see a marked improvement in the quality of your code.
  • A good controller unit test runs fast. We are talking 2000 unit tests all running within 10 seconds.
  • It's nearly impossible to test-drive code that ends up with a bad design. (Once again bad code is hard to test)
  • Pay attention to pain. If your tests become painful to maintain, there's something wrong.
  • Correctly managed design and tests enable sustained speed of development whereas poor testing techniques cause development to slow down to a point where testing is abandoned.

Some of the key take aways: use mocks, and testing should be helpful to your development process not a hindrance.

Don't write unit tests just to write them or just to get the necessary coverage. Make sure that you write the test cases with a specific intent and that they are written well so that you will continue to maintain and execute them as a part of your CI build process.

Here are some unit tests that I've recently written that I'd like to use to show some concrete cases.

[Test]

public void TestGetConfigValue_ValueExistsRequiredTrue()

{

    string key = "83F216CD-1B3E-4fc1-9DA5-4A7D506AF7E8";

    string expectedValue = "C2D4E7CA-BE6B-4976-BFA9-50F5223C603A";

    ConfigurationManager.AppSettings[key] = expectedValue;

 

    string actualValue = ServiceConfigHelper.Instance.GetConfigValue(key, true);

    Assert.AreEqual(expectedValue, actualValue);

}

 

[Test]

public void TestGetConfigValue_ValueExistsRequiredFalse()

{

    string key = "0601AB1F-C78C-4c72-8648-B140D50BDDEC";

    string expectedValue = "92DCADBC-9618-49f3-A412-5C90A945903D";

    ConfigurationManager.AppSettings[key] = expectedValue;

 

    string actualValue = ServiceConfigHelper.Instance.GetConfigValue(key, false);

    Assert.AreEqual(expectedValue, actualValue);

}

 

[Test]

public void TestGetConfigValue_ValueDoesntExistRequiredFalse()

{

    string key = "2D4B5C66-BA37-4ab8-9B51-3F17CF348E6D";

 

    string actualValue = ServiceConfigHelper.Instance.GetConfigValue(key, false);

    Assert.IsNull(actualValue);

}

 

[ExpectedException(typeof(ConfigurationErrorsException))]

[Test]

public void TestGetConfigValue_ValueDoesntExistRequiredTrue()

{

    string key = "0511216E-3AA6-4b80-B215-E980A459466D";

 

    // ConfigurationErrorsException here

    string actualValue = ServiceConfigHelper.Instance.GetConfigValue(key, true);

}

 

[ExpectedException(typeof(ArgumentNullException))]

[Test]

public void TestGetConfigValue_KeyIsNull_RequiredFalse()

{

    string actualValue = ServiceConfigHelper.Instance.GetConfigValue(null, false);

}

 

[ExpectedException(typeof(ArgumentNullException))]

[Test]

public void TestGetConfigValue_KeyIsNull_RequiredTrue()

{

    string actualValue = ServiceConfigHelper.Instance.GetConfigValue(null, true);

}

 

// Setup method here

[SetUp]

public void Reset()

{

    ServiceConfigHelper.Instance.Reset();

    if (ConfigurationManager.AppSettings.HasKeys())

    {

        List<string> allKeys = new List<string>();

        foreach (string key in ConfigurationManager.AppSettings.Keys)

        {

            allKeys.Add(key);

        }

 

        foreach (string key in allKeys)

        {

            ConfigurationManager.AppSettings[key] = string.Empty;

        }

    }

}

Notice that each of these has a very descriptive name, if you saw the name of the test in the list of failed test cases you immediately know what to work on; you don't even have to look at the test. Notice that all of the tests are pretty small, and that each test case tests a very specific piece of functionality. Also you might have noticed that I use Guids in test cases I like to do this just to make sure that I have random data and that test cases don't conflict with each other.

Also I'd like to note that in the book the guys recommend reading Working Effectively with Legacy Code for good coverage of unit testing, I haven't read it but I might grab a copy.

 

Sayed Ibrahim Hashimi

Wednesday, December 09, 2009 6:37:17 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Monday, December 07, 2009

A while back someone asked me if you could sync 2 or more folders with one statement using MSDeploy. I said of course, if you perform the sync using manifest files. Manifest files allow you to "group" sync operations into a file. When you invoke msdeploy.exe and point it to a manifest file, each provider will be executed in the order in which it appears inside the manifest file. A common scenario for using manifest files is to sync websites. This way you can specify the files that should be synced, the website (application) name, ACL values, etc. But you are not limited to using manifest files for web related sync operations. When using manifest files, you would specify the provider to be manifest. We will see this in the command used to snyc two folders. Often times when using a manifest file for the source you will also use one for the destination. Here are the two files.

SourceManifest.xml

<sitemanifest>

  <contentPath path="C:\temp\MSDeploy\Source01"/>

  <contentPath path="C:\temp\MSDeploy\Source02" />

</sitemanifest>

DestManifest.xml

<sitemanifest>

  <contentPath path="E:\temp\MSDeploy\Source01" />

  <contentPath path="E:\temp\MSDeploy\Source02" />

</sitemanifest>

In this example I am syncing two folders C:\temp\MSDeploy\Source01 and C:\temp\MSDeploy\Source02 to another drive location on E. The command to perform the sync would be

msdeploy -verb:sync -source:manifest=sourceManifest.xml -dest:manifest=destManifest.xml

And here are the results of that sync operation, when the destination directories don't exist.

C:\temp\MSDeploy>msdeploy -verb:sync -source:manifest=sourceManifest.xml -dest:manifest=destManifest.xml

Info: Adding sitemanifest (sitemanifest).

Info: Adding contentPath (E:\temp\MSDeploy\Source01).

Info: Adding dirPath (E:\temp\MSDeploy\Source01).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\01.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\02.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\03.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\04.txt).

Info: Adding contentPath (E:\temp\MSDeploy\Source02).

Info: Adding dirPath (E:\temp\MSDeploy\Source02).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\01.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\02.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\03.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\04.txt).

Total changes: 13 (13 added, 0 deleted, 0 updated, 0 parameters changed, 0 bytes copied)

As you can see the destination directories were created and the files synced into the destination folders. First all the content of the Source01 folder is synced and then the Source02 folder as expected. If you perform the sync operation and all files are up-to-date then no changes will be made.

This is just a very basic example of how you can use MSDeploy manifest files to perform a sync operation, but you can create manifest files that perform many different actions. Visual Studio 2010 uses manifest files when it creates the web packages for deployment.

 

Sayed Ibrahim Hashimi

Monday, December 07, 2009 4:50:37 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Thursday, November 19, 2009

I have a new video posted discussing MSBuild, you can see this video at http://www.dnrtv.com/default.aspx?showNum=158. This is a continuation of my first appearance discussing on dnrtv.com. Take a look and let me know if there are any particular topics you'd like for me to discuss. One of the topics I discuss in this video is Open Source MSBuild tasks. One of the most useful task libraries is the MSBuild Extension Pack, there is a great set of tasks there. If you haven't seen it already you should take a look.

Sayed Ibrahim Hashimi

dnrTV | msbuild | Video
Thursday, November 19, 2009 3:20:40 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Friday, November 13, 2009

The other day someone sent me an email asking me about reserved characters in MSBuild targets names. I didn't actually know of a published list of such a reference so I contacted the MSBuild team for more information and here is what I found out.

Illegal characters in target names

'$', '@', '(', ')', '%', '*', '?', '.'

Properties, items and item metadata elements must start with either a letter [a-Z] or an underscore (_).

Characters after the initial character for properties, items and item metadata can include: letters, numbers, underscore, and dashes (-).

 

Sayed Ibrahim Hashimi

Friday, November 13, 2009 7:36:00 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
Saturday, November 07, 2009

A while back I had a session on MSDeploy where I demonstrated deploying an ASP.NET MVC Sudoku solver that I wrote a while back. A few people asked me to publish it, so I did you can get it at http://sudokumvc.codeplex.com/

 

Sayed Ibrahim Hashimi

Saturday, November 07, 2009 9:51:27 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 

Theme design by Jelle Druyts