BDD Style Test Phrasing… What’s Your Poison?

I’ve had this question come up a few times recently, and I wanted to get everybody’s take on it…  when you write BDD style tests, what practice do you prefer?

…I’ll have a follow up to this poll in a few days and explain some of my own reasoning to the whole situation.

WebStorm JavaScripting & Noding Workflow Webinar Recording

Today the JetBrains team wrapping up final processing for my webinar from last week. You can check out the webinar via their JetBrains Youtube Channel:

JavaScriptFor even more information be sure to check out the questions and answers on the JetBrain WebStorm IDE blog entry. Some of the questions include:

  • Q: How to enable Node.js support in PhpStorm (PyCharm, IntelliJ IDEA, RubyMine)?
  • Q:How to enable autocompletion for Express, Mocha and other libraries?
  • Q: Is it possible to debug a Node.js application that runs remotely? Is it possible to debug when your node and the rest of the dependencies (database, etc.) are running in a VM environment like Vagrant?
  • Q: Does the debugger support cluster mode?

…and others all here.

Exam 70-515 Pt 1 Focus on Developing Web Forms Pages

I’m going to be taking the Web Application Development with Microsoft .NET Framework 4 in the very near future.  Since I’m going to be scribbling a few notes and studying up, it seemed like I’d publish my studies.  With that, here is round 1.  My intent is to study each focus area and make a blog post about it.  Beware, these could be some rather messy blog entries, I’ll try to keep them somewhat cohesive though. (Note, the base of these notes are from the actual 70-515 curriculum and also Niall Merrigan’s Blog Entry “MCTS Web Applications .NET 4 – 70-515 – Objectives List Part 1” helped a lot!  I’ve of course added my extra 2 cents to most of these.  Cheers!)

Focus Point:  Developing Web Forms Pages

Configure Web Forms Pages

A page directive is a page-specific attribute used by the ASP.NET page parser and compiler.  Some of these attributes I’ve linked and detailed below:

  • Page.AsyncMode Property – Sets a value indicating the page is processed synchronously or asynchronously.  The AsyncMode property is set by the Page parser when code for the page is generated. Use the Async attribute in @ Page directive to set this value.  Asynchronous pages do not work when the AspCompat attribute is set to true or the Transaction attribute is set to a value other than Disabled in the @ Page directive.
  • Page.AsyncTimeout Property – Gets or sets a value indicating the time-out interval used when processing asynchronous tasks.  The asynchronous time-out of the page represents the amount of time that the page will wait to perform asynchronous tasks. In most circumstances, do not set this property in code. Set the page asynchronous time-out interval using the pages element of the Web configuration file or in the @ Page directive. Values set in the page configuration section are overwritten by the page directive.  Define your asynchronous task using the PageAsyncTask class and register a beginning, an ending, and a time-out handler. If the asynchronous task does not complete in the time interval specified, the time-out handler will be invoked.
  • Page.AspCompatMode Property – Sets a value indicating whether the page can be executed on a single-threaded apartment (STA) thread.  This allows the page to call STA components, such as components developed with Visual Basic 6.0. Setting this property to true also allows the page to call COM+ components that require access to the unmanaged ASP built-in objects. These are accessible through the ASP ObjectContext object or the OnStartPage method.  In most circumstances, do not set this property in code. Set the aspcompat attribute to true using the @ Page directive in the .aspx file. When the page is requested, the dynamically generated class sets the property.
  • Page.Buffer Property – Sets a value indicating whether the page output is buffered.  In most circumstances, do not set this property in code. Set the Buffer attribute to true using the @ Page directive in the .aspx file. When the page is requested, the dynamically generated class sets the property.
  • Control.ClientIDMode Property – Gets or sets the algorithm that is used to generate the value of the ClientID property.  The values are AutoID which generates the value by concatenating the ID values of each parent naming container with the ID value of the control, seperated by an underscore character.  The Static value sets the value statically and makes the control the top of the hierarchy of naming containers if it is a container.  Predictable algorithm is used for controls that are data-bound controls and concatenates the ClientID value of the parent with the ID value of the control.  Inherit sets it to the parent control.
  • Page.ClientTarget Property – Gets or sets a value that allows you to override automatic detection of browser capabilities and to specify how a page is rendered for particular browser clients.  If you do not set the ClientTarget property, the HttpBrowserCapabilities object associated with the Page.Request property reflects the browser capabilities associated with the value (alias) that you provide.  uplevel, which specifies
  • CompilationMode Enumeration – Defines constants that specify how ASP.NET should compile .aspx pages and .ascx controls.  Members include; Auto sets ASP.NET to not compile the page if possible, Never states the page will not be dynamically compiled, and Always sets ASP.NET to compile every time.
  • Control.EnableViewState Property – This one has been the disdain of many serious web developers, as the view state becomes a horrifying beast to deal with.  But I digress, it may appear on the test so know about it.  🙂  This property gets or sets a value indicating whether the server control persists its view state, and the view state of any child controls it contains, to the requesting client.
  • Page.EnableViewStateMac Property – Gets or sets a value indicating whether ASP.NET should check message authentication codes (MAC) in the page’s view state when the page is posted back from the client.
  • Page.ErrorPage Property – Gets or sets the error page to which the requesting browser is redirected in the event of an unhandled page exception.
  • Page.MasterPageFile Property – Gets or sets the file name of the master page.
  • Page.MetaDescription – Gets or sets the content of the “description” meta element.
  • Page.MetaKeywords – Gets or set the content of the “keywords” meta element.
  • Page.Theme Property – Gets or sets the name of the page theme.
  • ViewStateEncryptionMode Enumberation – Specifies whether view-state information is encrypted;  Auto sets the encryption by calling the RegisterRequiresViewStateEncryption method, Always sets it to encrypt always and Never does not encrypt even if the control requests it.
  • Control.ViewState Property – Gets or sets the view-state mode of this control.
  • Control.ViewStateMode Property – Gets or sets the view-state mode of this control.
  • Compiler.WarningLevel Property – Gets the compiler warning level.
  • Saving and reading values in View State:  Save Values / Read Values
  • Auto Event Wire Up – i.e. ASP.NET Web Server Control Event Model.
  • PageSection.EnableEventValidation Property – Gets or sets a value that specifies whether event validation is enabled.
  • General configuration settings (ASP.NET) – This topic covers web.config files and setting up configuration sections within this file.  Some of the topics to be familiar with include; connectionStringssystem.web, configSections, appSettings, location, System.Configuation, and System.Web.Configuration.
  • XHTML Standards in Visual Studio and ASP.NET
  • Editing ASP.NET Configuration Files – Case-sensitivity, custom sections, remote configuration files, etc.
  • Making controls easier to access via JavaScript since they’re often cryptic…  Walkthrough:  Making Controls Located in Web User Controls Easier to Access from JavaScript, How to:  Access Controls from JavaScript by ID, and Walklthrough:  Making Data-Bound Controls Easier to Access from JavaScript.

Implement Master Pages and Themes

Implement Globalization

Handle Page Life Cycle Events

Implement Caching

There are a few more topics for this section of the test, I’ll follow up with the remainder of those notes, and move on to the next topic section.  Enjoy…

Test Driven Development Built Name Generator Part 3

Part 1, Part 2.

Now it is time finally for the random name generation.  I’ve gotten everything into place, so it’s just a matter of grabbing the names and randomizing among them.  Just as a check, after Part 2 was finished I had a total of 98,572 rows of data, or simply 98,572 names.

Many times I would not write actual unit tests against the database as it breaks isolation.  This time though, I’m making an exception.  First I added a reference to Generator.Core, System.Data, and System.Data.Entity.  I then created a new unit test class called DatabaseTests and added the following test to get things rolling.  Keep in mind, since these tests break isolation, I don’t write them in the red light green light idea of TDD.  My assumption is that they only prove the database is setup, running, the connection string is correct, and other minor configuration based and server based components.  In addition, yes, these are somewhat silly tests, such as the RetrieveFirstName() test has a bit of redundancy to it, but the point is to have an automated test to assure that the data has been moved into the database and is returning appropriately.

[sourcecode language=”csharp”]
[TestClass]
public class DatabaseTests
{
[TestMethod]
public void RetrieveFirstFemaleName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Female First Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty);
}

[TestMethod]
public void RetrieveLastName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Last Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty);
}

[TestMethod]
public void RetrieveFirstMaleName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Male First Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty);
}

[TestMethod]
public void RetrieveFirstName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Female First Names" || name.Type == "Male First Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty && returnName.Type == "Female First Names" ||
returnName.Type == "Male First Names");
}
}
[/sourcecode]

The next step now was to refactor the existing tests to prove the assembly of the name data transfer objects that would hold the first name and last name derived from the returned entity objects.

The first thing I did was break out the actual name objects into their respective files.  I did this using ReSharper, because it’s super insanely simple with ReSharper.  After that I put the class files in the project that has the model.  Next I fixed the namespaces to Generator.Core.Model.  The class files after these changes looked like the code below.

IFullName.c

[sourcecode language=”csharp”]
namespace Generator.Core.Model
{
public interface IFullName
{
string FirstName { get; set; }
string LastName { get; set; }
}
}
[/sourcecode]

FullName.cs

[sourcecode language=”csharp”]
namespace Generator.Core.Model
{
public class FullName : IFullName
{
public FullName()
{
FirstName = string.Empty;
LastName = string.Empty;
}

#region IFullName Members

public string FirstName { get; set; }
public string LastName { get; set; }

#endregion
}
}
[/sourcecode]

NameFactory.cs

[sourcecode language=”csharp”]
namespace Generator.Core.Model
{
public class NameFactory
{
public static IFullName Build()
{
return new FullName {FirstName = "TestFirst", LastName = "TestLast"};
}
}
}
[/sourcecode]

Now that we have these files moved out to the project where all the munging will happen, I’m going to start the actual refactor of the tests.  What I’ve come up with for the test refactor is as follows.

[sourcecode language=”csharp”]
using Generator.Core.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Factory.Tests
{
[TestClass]
public class FactoryNameBuilder
{
[TestMethod]
public void VerifyFullNameObjectInstantiatesWithNames()
{
var name = new FullName();
Assert.IsTrue(name.FirstName.Length == 0);
Assert.IsTrue(name.LastName.Length == 0);
}

[TestMethod]
public void VerifyFullNameObjectReturnsFromFactory()
{
var factory = new NameFactory();
IFullName name = factory.Build();
Assert.IsTrue(name.FirstName.Length > 0);
Assert.IsTrue(name.LastName.Length > 0);
}

[TestMethod]
public void VerifyFullNameIsRandom()
{
var factory = new NameFactory();
IFullName nameOne = factory.Build();
IFullName nameTwo = factory.Build();

Assert.AreNotEqual(nameOne.FirstName, nameTwo.FirstName);
Assert.AreNotEqual(nameOne.LastName, nameTwo.LastName);
}
}
}
[/sourcecode]

In the factory I removed the fake return and fleshed out the appropriate build method.

[sourcecode language=”csharp”]
using System;
using System.Collections.Generic;
using System.Linq;

namespace Generator.Core.Model
{
public class NameFactory
{
public IFullName Build()
{
Random rand = new Random(DateTime.Now.Millisecond);

GeneratorEntities entities = new GeneratorEntities();

List FirstNames = (from name in entities.Names
where name.Type == "Female First Names" || name.Type == "Male First Names"
select name).ToList();
List LastNames = (from name in entities.Names
where name.Type == "Last Names"
select name).ToList();

FullName fullName = new FullName();
fullName.FirstName = FirstNames[rand.Next(0, FirstNames.Count)].Name;
fullName.LastName = LastNames[rand.Next(0, LastNames.Count)].Name;

return fullName;
}
}
}
[/sourcecode]

Run the tests now and you have a random name gold mine.  However, I wanted a bit more than that.  With another test added…

[sourcecode language=”csharp”]
[TestMethod]
public void VerifyMultipleNameReturn()
{
var factory = new NameFactory();
List<IFullName> list = factory.Build(1000);

for (int i = 0; i < list.Count; i++)
{
int compareUp = i + 1;
if (compareUp == list.Count)
{
compareUp = 0;
}
Assert.AreNotEqual(list[compareUp].FirstName + list[compareUp].LastName, list[i].FirstName + list[i].LastName);
}
}
[/sourcecode]

…then the extra Build method.

[sourcecode language=”csharp”]
public List<IFullName> Build(int numberOfNames)
{
var rand = new Random(DateTime.Now.Millisecond);
var entities = new GeneratorEntities();

List<Names> FirstNames = (from name in entities.Names
where name.Type == "Female First Names" || name.Type == "Male First Names"
select name).ToList();
List<Names> LastNames = (from name in entities.Names
where name.Type == "Last Names"
select name).ToList();

var names = new List<IFullName>();

for (int i = 0; i < numberOfNames; i++)
{
var fullName = new FullName();
fullName.FirstName = FirstNames[rand.Next(0, FirstNames.Count)].Name;
fullName.LastName = LastNames[rand.Next(0, LastNames.Count)].Name;
names.Add(fullName);
}

return names;
}
[/sourcecode]

and now I have a strong verification that I get solid randoms for 1000 name pairs.  I bumped it up to 2000 too just for fun, and didn’t hit duplicates until I put it up to 200,000.

Test Driven Development Built Name Generator Part 2

Part 1Part 3.

Alright, time to tear into getting that name data imported into the database.  To review the previous entry check out part 1.

Next I set the Windows App Project I added in part 1 to be the startup project.  After that I created a screen that looks like the image below (click to see larger image).

Also add an open file dialog control.  Next double click on the Process button and add the following code.  Make sure not to miss the instantiation of the names list property in the initialization.

[sourcecode language=”csharp”]
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace TextFileImporter
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Names = new List();
}

private List Names { get; set; }

private void buttonProcessFile_Click(object sender, EventArgs e)
{
if (openFile.ShowDialog() == DialogResult.OK)
{
if (File.Exists(openFile.FileName))
{
TextReader tr = new StreamReader(openFile.FileName);
textProcessedFile.Text = tr.ReadToEnd();
tr.Close();
// Cleanup text.
textProcessedFile.Text = ProcessName(textProcessedFile.Text);
}
else
{
MessageBox.Show("Select a file that exists.", "File doesn’t exist.", MessageBoxButtons.OK,
MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
}
}

private string ProcessName(string textBody)
{
var regex = new Regex("[^A-Z’]+");
textBody = regex.Replace(textBody, " ");

foreach (var s in textBody.Split(Convert.ToChar(" ")))
{
Names.Add(s);
}

return textBody;
}
}
}
[/sourcecode]

With the beauty of those regular expressions the files will parse appropriately in about 1-5 seconds.  Next we need a way to write this data into the database.  I did this by adding a Class Project named Generator.Core and added a folder called Model.

In the Model Directory I added a new ADO.NET Entity Framework Model.  The images below show my steps through the wizard.

  • Wizard # 1 - Adding Data Model.Wizard # 1 – Adding Data Model.
  • Wizard # 2 - Adding Data Model.Wizard # 2 – Adding Data Model.
  • Wizard # 3 - Adding Data Model.Wizard # 3 – Adding Data Model.
  • Wizard # 4 - Adding Data Model.Wizard # 4 – Adding Data Model.
  • Wizard # 5 - Adding Data Model.Wizard # 5 – Adding Data Model.

.smugcontainer div {overflow: hidden;line-height: 1.1;margin-top: 10px;font-family: verdana, arial, lucida, sans-serif;font-size: 85%;background-color1: rgb(20, 20, 20);}
.smugimg li {float: left;display: block;width: 160px;height: 200px;background-position: 50% 50%;margin-right: 10px;margin-bottom: 10px;}
.smugimg li img {width: auto; height: auto; border: solid 1px #aaa; background: #555; padding: 2px; vertical-align: middle;}
.smugimg a {display: block;text-align: center;text-decoration: none; color1: rgb(240,240,240);}
.smugimg a:hover img {border: 3px solid #6da6d1; padding: 0px;}

.smugcontainer div {overflow: hidden;line-height: 1.1;margin-top: 10px;font-family: verdana, arial, lucida, sans-serif;font-size: 85%;background-color1: rgb(20, 20, 20);}
.smugimg li {float: left;display: block;width: 160px;height: 200px;background-position: 50% 50%;margin-right: 10px;margin-bottom: 10px;}
.smugimg li img {width: auto; height: auto; border: solid 1px #aaa; background: #555; padding: 2px; vertical-align: middle;}
.smugimg a {display: block;text-align: center;text-decoration: none; color1: rgb(240,240,240);}
.smugimg a:hover img {border: 3px solid #6da6d1; padding: 0px;}

At the end I also deleted the Class1.cs file from the project.

I then added a reference to the Generator.Core Project in the TextFileImporter Application Project.  Next add an application configuration file to the TextFileImporter Project with the following configuration section.

[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="GeneratorEntities" connectionString="metadata=res://*/Model.Data.csdl|res://*/Model.Data.ssdl|res://*/Model.Data.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\carriage;Initial Catalog=Generator;Integrated Security=True;Pooling=False;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
[/sourcecode]

At the last minute, and to make sure anyone following along with these instructions is really paying attention, I made a minor change to the database table.  I changed the column Type to a data type of nvarchar(50).  I then updated the Data.edmx file in the Generator.Core Project.  To do this open up the file and right click anywhere in the white space around the model.  Then click on Update Model from Database….  Now, as things go, the stupid model didn’t update for me.  This is something that seems to occur very frequetly with the ADO.NET Entity Framework Model Files.  Since it didn’t update I had to manually right click on the Type Property and then set the Type of the Type (yes I know, redundant naming) to String.

So if anyone from Microsoft is reading this, the entity model files are STILL broken for some reason.  It’s been about 6 months since the entity framework and such where in beta and they still behave in many ways like they’re in beta, please fix this.  k thx bye.

Next I double clicked the Save (buttonSaveToDb) button and entered the following code to write the file data into the database.

[sourcecode language=”csharp”]
private void buttonSaveToDb_Click(object sender, EventArgs e)
{
if (comboNameType.Text == string.Empty)
{
MessageBox.Show("Select a type of name.", "Select Name", MessageBoxButtons.OK,
MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
else
{
// TODO Write to DB.
var generatorEntities = new GeneratorEntities();
foreach (var name in Names)
{
var newName =
new Names
{
NameId = Guid.NewGuid(),
Name = name,
Type = comboNameType.Text
};
generatorEntities.AddToNames(newName);
}
generatorEntities.SaveChanges(true);
}
}
[/sourcecode]

Then a quick reference and that finishes up the TextFileImporter Project.

[sourcecode language=”csharp”]
using Generator.Core.Model;
[/sourcecode]

Now mind you, I broke TDD principles because this app was merely a utility, would be used a few times, and above all breaks isolation and crosses boundaries.  A good rule is to not write tests for a project like this.  Unless you feel it absolutely necessary then I wouldn’t even think of it.

Now run the application and open and import each of the three files into the database.  This will give us the data we need for the next step of our random name generator.