tag:blogger.com,1999:blog-26815740407964765592024-02-19T09:51:50.808-06:00new Christian(new Developer()).Thoughts;A software developer's worldview from a christian perspective.Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comBlogger30125tag:blogger.com,1999:blog-2681574040796476559.post-19396457284012299652015-07-18T16:33:00.004-05:002015-07-18T16:33:46.844-05:00New Blog<div class="separator" style="clear: both; text-align: center;">
<a href="https://cloud.githubusercontent.com/assets/177508/8763596/9b432186-2d6a-11e5-8083-45480079179e.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://cloud.githubusercontent.com/assets/177508/8763596/9b432186-2d6a-11e5-8083-45480079179e.png" width="320" /></a></div>
<br />
<br />
For those of you that have been following this blog for a while, I wanted you to know that I have created a new blog that I will be posting to more frequently. You can find it <a href="http://qualitysoftwarematters.com/" target="_blank">here</a>.<br />
<br />
Hope you enjoy!Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-29718456946954547782014-05-25T20:47:00.001-05:002014-05-25T20:49:13.575-05:00Data Integration Tests and Transactions - Part 2<!DOCTYPE html>
<html>
<head>
<title>2014-05-25_data_integration_tests_and_multiple_data_framework_transactions</title>
<style>
/*
Name: GeekPark article style for Mou app
Author: hzlzh(hzlzh.dev@gmail.com)
URL: https://github.com/GeekPark/Doc/blob/master/GeekPark/GeekPark-Style-for-Mou.css
*/
body{ font-family:"Microsoft Yahei","Helvetica Neue","Luxi Sans","DejaVu Sans",Tahoma,"Hiragino Sans GB",STHeiti; font-size:14px; line-height:1.6; color:#666666; padding-top:10px; padding-bottom:10px; background-color:white; padding:30px; }
body > *:first-child{ margin-top:0 !important; }
body > *:last-child{ margin-bottom:0 !important; }
a{ color:#109EFF; text-decoration:none; }
a:hover{ border-bottom:1px dotted #109EFF; }
a:visited, a:active{ color:#109EFF; }
a.absent{ color:#cc0000; }
a.anchor{ display:block; padding-left:30px; margin-left:-30px; cursor:pointer; position:absolute; top:0; left:0; bottom:0; }
p a{ margin:0 2px; }
h1, h2, h3, h4, h5, h6{ color:#333333; margin:20px 0 10px; padding:0; font-weight:bold; -webkit-font-smoothing:antialiased; cursor:text; position:relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor{ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center; text-decoration:none; }
h1 tt, h1 code{ font-size:inherit; }
h2 tt, h2 code{ font-size:inherit; }
h3 tt, h3 code{ font-size:inherit; }
h4 tt, h4 code{ font-size:inherit; }
h5 tt, h5 code{ font-size:inherit; }
h6 tt, h6 code{ font-size:inherit; }
h1{ font-size:18px; font-weight:bold; line-height:22px; margin-bottom:5px; color:#333; }
h2{ font-size:16px; font-weight:bolder; line-height:18px; margin:20px 0; }
h3{ font-size:14px; }
h4{ color:#666; font-size:14px; font-weight:bolder; line-height:18px; margin:20px 0; }
h5{ font-size:14px; }
h6{ color:#777777; font-size:14px; }
p, blockquote, ul, ol, dl, li, table, pre{ margin:15px 0; line-height:150%; }
hr{ background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0; border:0 none; color:#cccccc; height:4px; padding:0; }
body > h2:first-child{ margin-top:0; padding-top:0; }
body > h1:first-child{ margin-top:0; padding-top:0; }
body > h1:first-child + h2{ margin-top:0; padding-top:0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child{ margin-top:0; padding-top:0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6{ margin-top:0; padding-top:0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p{ margin-top:0; }
li p.first{ display:inline-block; }
li{ font-size:14px; line-height:150%; margin-bottom:5px; margin-top:0; }
ul, ol{ padding-left:30px; }
ul :first-child, ol :first-child{ margin-top:0; }
dl{ padding:0; }
dl dt{ font-size:14px; font-weight:bold; font-style:italic; padding:0; margin:15px 0 5px; }
dl dt:first-child{ padding:0; }
dl dt > :first-child{ margin-top:0; }
dl dt > :last-child{ margin-bottom:0; }
dl dd{ margin:0 0 15px; padding:0 15px; }
dl dd > :first-child{ margin-top:0; }
dl dd > :last-child{ margin-bottom:0; }
blockquote{ background:url("data:image/png;base64,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") no-repeat scroll left 11px transparent; color:#999999; margin-left:28px; min-height:30px; padding:17px 40px 0; }
blockquote p{ color:#999999 !important; margin-bottom:25px !important; }
blockquote > :first-child{ margin-top:0; }
blockquote > :last-child{ margin-bottom:0; }
table{ padding:0; border-collapse:collapse; }
table tr{ border-top:1px solid #cccccc; background-color:white; margin:0; padding:0; }
table tr:nth-child(2n){ background-color:#f8f8f8; }
table tr th{ font-weight:bold; border:1px solid #cccccc; text-align:left; margin:0; padding:6px 13px; }
table tr td{ border:1px solid #cccccc; text-align:left; margin:0; padding:6px 13px; }
table tr th :first-child, table tr td :first-child{ margin-top:0; }
table tr th :last-child, table tr td :last-child{ margin-bottom:0; }
img{ border:1px solid #E1E1E1; margin:0 auto 10px; display:block; max-width:512px; padding:5px; }
span.frame{ display:block; overflow:hidden; }
span.frame > span{ border:1px solid #dddddd; display:block; float:left; overflow:hidden; margin:13px 0 0; padding:7px; width:auto; }
span.frame span img{ display:block; float:left; }
span.frame span span{ clear:both; color:#333333; display:block; padding:5px 0 0; }
span.align-center{ display:block; overflow:hidden; clear:both; }
span.align-center > span{ display:block; overflow:hidden; margin:13px auto 0; text-align:center; }
span.align-center span img{ margin:0 auto; text-align:center; }
span.align-right{ display:block; overflow:hidden; clear:both; }
span.align-right > span{ display:block; overflow:hidden; margin:13px 0 0; text-align:right; }
span.align-right span img{ margin:0; text-align:right; }
span.float-left{ display:block; margin-right:13px; overflow:hidden; float:left; }
span.float-left span{ margin:13px 0 0; }
span.float-right{ display:block; margin-left:13px; overflow:hidden; float:right; }
span.float-right > span{ display:block; overflow:hidden; margin:13px auto 0; text-align:right; }
code, tt{ margin:0 2px; padding:0 5px; white-space:nowrap; border:1px solid #eaeaea; background-color:#f8f8f8; border-radius:3px; }
pre code{ margin:0; padding:0; white-space:pre; border:none; background:transparent; }
.highlight pre{ background-color:#f8f8f8; border:1px solid #cccccc; font-size:13px; line-height:19px; overflow:auto; padding:6px 10px; border-radius:3px; }
pre{ background-color:#f8f8f8; border:1px solid #cccccc; font-size:13px; line-height:19px; overflow:auto; padding:6px 10px; border-radius:3px; }
pre code, pre tt{ background-color:transparent; border:none; }
@media screen and (min-width: 914px){
body{ width:854px; margin:0 auto; }
}
</style>
</head>
<body>
<p><a href="http://toddmeinershagen.blogspot.com/2014/05/data-integration-tests-and-transactions.html">Last time</a> I talked about how to use the <a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx">TransactionScope</a> class to handle the rollback of any changes made during a data integration test. This time, I would like to talk about another issue that will eventually come up using transactions: using <a href="http://msdn.microsoft.com/en-us/data/ef.aspx">Entity Framework</a> code-first in combination with any other data access framework while leveraging TransactionScope.</p>
<p>In our case, we use <a href="https://code.google.com/p/dapper-dot-net/">Dapper</a> to insert data before our tests and to assert things about the state of the database after exercising the <a href="http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx">code-first Entity Framework</a> data layer functionality we are testing. Below is our example.</p>
<pre><code>private TransactionScope _scope;
[SetUp]
public void SetUp()
{
_scope = new TransactionScope();
}
[TearDown]
public void TearDown()
{
_scope.Dispose();
}
[Test]
public void test_to_demo_ef_and_dapper_connections()
{
var person = new Person {FirstName = "Todd", LastName = "Meinershagen"};
var sql = "INSERT INTO dbo.Persons (FirstName, LastName) ";
sql = sql + "VALUES (@FirstName, @LastName)";
using (var connection = new SqlConnection("a connection string"))
{
connection.Execute(sql, person);
}
var db = new PersonContext();
var matchingPersons =
from p in db.Persons
where
(p.FirstName == person.FirstName) &&
(p.LastName == person.LastName)
select p;
matchingPersons.FirstOrDefault().Should().NotBeNull();
}
</code></pre>
<p>Both Dapper and EF establish their own connections, and we would expect that each connection would take part in the ambient transaction being created during the [SetUp] of our test fixture. </p>
<p>Normally, this is not an issue, but when the tests are run, we get a message similar to below:</p>
<pre><code>MSDTC on server 'servername' is unavailable.
</code></pre>
<p>This can occur for any number of reasons such as the following:</p>
<ul>
<li>Opening multiple connections with same connection string to SQL Server 2005.</li>
<li>Opening multiple nested connections with same connection string to SQL Server 2008.</li>
<li>Opening multiple connection to two different SQL Server 2008 instances.</li>
</ul>
<p>In the case of our tests, we are making two connections (one for EF and one for Dapper) to SQL Server 2008 using the same connection string. Based on the guidance above, this should not force our system to escalate to MSDTC. </p>
<p>So, what is happening here?</p>
<p>After searching diligently on the internet (thank God for the internet!), I found an <a href="http://stackoverflow.com/questions/18088949/entityframeworkmue-in-entity-framework">article</a> explaining that Microsoft cleverly adds information to a code-first connection string to allow Microsoft to collect statistics from those using Azure and Entity Framework to determine what percentage use code-first as opposed to database-first. (Why Microsoft, why?) This is supposed to have been fixed in EF 6.0.</p>
<p>So, instead of using a connection string as you specified:</p>
<pre><code>Data Source=(local);
Initial catalog=LocalDb;
Integrated Security=True;
</code></pre>
<p>The system uses the following for EF:</p>
<pre><code>Data Source=(local);
Initial catalog=LocalDb;
Integrated Security=True;
Application Name=EntityFrameworkMUE
</code></pre>
<p>So, what does this mean?</p>
<p>Unfortunately, this causes our system to see the two connections (Dapper and EF) as two different connection strings and therefore, it looks like you are connecting to two different data sources which escalate to MSDTC. What a pain!</p>
<p>So, how do we get around this issue.</p>
<p>One way would be to use EF for both production and test code, although this robs us of the benefit of quickly setting up data using a light-weight framework like Dapper. Another option is to modify our test project’s configuration file by explicitly specifying the Application Name for our connection string. The system will then see the two connections as the same. No more escalation to MSDTC!</p>
<p>Hope this helps.</p>
</body>
</html>Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-59223535422886774972014-05-23T02:31:00.001-05:002014-05-25T20:58:09.122-05:00Data Integration Tests and Transactions - Part 1<html>
<head>
<title>2014-05-25_integration_tests_and_transactions</title>
<style>
/*
Name: GeekPark article style for Mou app
Author: hzlzh(hzlzh.dev@gmail.com)
URL: https://github.com/GeekPark/Doc/blob/master/GeekPark/GeekPark-Style-for-Mou.css
*/
body{ font-family:"Microsoft Yahei","Helvetica Neue","Luxi Sans","DejaVu Sans",Tahoma,"Hiragino Sans GB",STHeiti; font-size:14px; line-height:1.6; color:#666666; padding-top:10px; padding-bottom:10px; background-color:white; padding:30px; }
body > *:first-child{ margin-top:0 !important; }
body > *:last-child{ margin-bottom:0 !important; }
a{ color:#109EFF; text-decoration:none; }
a:hover{ border-bottom:1px dotted #109EFF; }
a:visited, a:active{ color:#109EFF; }
a.absent{ color:#cc0000; }
a.anchor{ display:block; padding-left:30px; margin-left:-30px; cursor:pointer; position:absolute; top:0; left:0; bottom:0; }
p a{ margin:0 2px; }
h1, h2, h3, h4, h5, h6{ color:#333333; margin:20px 0 10px; padding:0; font-weight:bold; -webkit-font-smoothing:antialiased; cursor:text; position:relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor{ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center; text-decoration:none; }
h1 tt, h1 code{ font-size:inherit; }
h2 tt, h2 code{ font-size:inherit; }
h3 tt, h3 code{ font-size:inherit; }
h4 tt, h4 code{ font-size:inherit; }
h5 tt, h5 code{ font-size:inherit; }
h6 tt, h6 code{ font-size:inherit; }
h1{ font-size:18px; font-weight:bold; line-height:22px; margin-bottom:5px; color:#333; }
h2{ font-size:16px; font-weight:bolder; line-height:18px; margin:20px 0; }
h3{ font-size:14px; }
h4{ color:#666; font-size:14px; font-weight:bolder; line-height:18px; margin:20px 0; }
h5{ font-size:14px; }
h6{ color:#777777; font-size:14px; }
p, blockquote, ul, ol, dl, li, table, pre{ margin:15px 0; line-height:150%; }
hr{ background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0; border:0 none; color:#cccccc; height:4px; padding:0; }
body > h2:first-child{ margin-top:0; padding-top:0; }
body > h1:first-child{ margin-top:0; padding-top:0; }
body > h1:first-child + h2{ margin-top:0; padding-top:0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child{ margin-top:0; padding-top:0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6{ margin-top:0; padding-top:0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p{ margin-top:0; }
li p.first{ display:inline-block; }
li{ font-size:14px; line-height:150%; margin-bottom:5px; margin-top:0; }
ul, ol{ padding-left:30px; }
ul :first-child, ol :first-child{ margin-top:0; }
dl{ padding:0; }
dl dt{ font-size:14px; font-weight:bold; font-style:italic; padding:0; margin:15px 0 5px; }
dl dt:first-child{ padding:0; }
dl dt > :first-child{ margin-top:0; }
dl dt > :last-child{ margin-bottom:0; }
dl dd{ margin:0 0 15px; padding:0 15px; }
dl dd > :first-child{ margin-top:0; }
dl dd > :last-child{ margin-bottom:0; }
blockquote{ background:url("data:image/png;base64,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") no-repeat scroll left 11px transparent; color:#999999; margin-left:28px; min-height:30px; padding:17px 40px 0; }
blockquote p{ color:#999999 !important; margin-bottom:25px !important; }
blockquote > :first-child{ margin-top:0; }
blockquote > :last-child{ margin-bottom:0; }
table{ padding:0; border-collapse:collapse; }
table tr{ border-top:1px solid #cccccc; background-color:white; margin:0; padding:0; }
table tr:nth-child(2n){ background-color:#f8f8f8; }
table tr th{ font-weight:bold; border:1px solid #cccccc; text-align:left; margin:0; padding:6px 13px; }
table tr td{ border:1px solid #cccccc; text-align:left; margin:0; padding:6px 13px; }
table tr th :first-child, table tr td :first-child{ margin-top:0; }
table tr th :last-child, table tr td :last-child{ margin-bottom:0; }
img{ border:1px solid #E1E1E1; margin:0 auto 10px; display:block; max-width:512px; padding:5px; }
span.frame{ display:block; overflow:hidden; }
span.frame > span{ border:1px solid #dddddd; display:block; float:left; overflow:hidden; margin:13px 0 0; padding:7px; width:auto; }
span.frame span img{ display:block; float:left; }
span.frame span span{ clear:both; color:#333333; display:block; padding:5px 0 0; }
span.align-center{ display:block; overflow:hidden; clear:both; }
span.align-center > span{ display:block; overflow:hidden; margin:13px auto 0; text-align:center; }
span.align-center span img{ margin:0 auto; text-align:center; }
span.align-right{ display:block; overflow:hidden; clear:both; }
span.align-right > span{ display:block; overflow:hidden; margin:13px 0 0; text-align:right; }
span.align-right span img{ margin:0; text-align:right; }
span.float-left{ display:block; margin-right:13px; overflow:hidden; float:left; }
span.float-left span{ margin:13px 0 0; }
span.float-right{ display:block; margin-left:13px; overflow:hidden; float:right; }
span.float-right > span{ display:block; overflow:hidden; margin:13px auto 0; text-align:right; }
code, tt{ margin:0 2px; padding:0 5px; white-space:nowrap; border:1px solid #eaeaea; background-color:#f8f8f8; border-radius:3px; }
pre code{ margin:0; padding:0; white-space:pre; border:none; background:transparent; }
.highlight pre{ background-color:#f8f8f8; border:1px solid #cccccc; font-size:13px; line-height:19px; overflow:auto; padding:6px 10px; border-radius:3px; }
pre{ background-color:#f8f8f8; border:1px solid #cccccc; font-size:13px; line-height:19px; overflow:auto; padding:6px 10px; border-radius:3px; }
pre code, pre tt{ background-color:transparent; border:none; }
@media screen and (min-width: 914px){
body{ width:854px; margin:0 auto; }
}
</style>
</head>
<body>
<p>I have been writing some integration tests in .NET lately to specify behavior for my data layer. The issue that always comes up is how to make sure that each test is completely isolated from other tests. This requires each test to initialize needed data and at the end to clean up any data that was created so that other tests are not impacted by it. In the past I have set up compensating queries to delete that same data on tear down.</p>
<p>This can create one of two problems:</p>
<ul>
<li><strong>maintainability</strong> - it is hard to maintain this logic going forward</li>
<li><strong>reliability</strong> - it doesn’t guarantee successful rollback of the initial inserts because the query could possibly fail leaving the tests in a position for unsuccessful future tests against the database</li>
</ul>
<p>So, what do you do?</p>
<p>I have been using the handy <a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx">TransactionScope</a> class to allow any connections to participate in the ambient transaction and then dispose of the transaction without committing on tear down of the fixture.</p>
<p>In the example below, I have used NUnit, but this could work with other testing frameworks quite well.</p>
<pre><code>[TestFixture]
public class MyFixture
{
private TransactionScope _scope;
[SetUp]
public void SetUp()
{
_scope = new TransactionScope();
}
[TearDown]
public void TearDown()
{
_scope.Dispose();
}
///<summary>This is a silly sample test for display purposes only.</summary>
[Test]
public void given_context_when_something_happens_should_have_expected_outcome()
{
ExecuteSomeLogicForInsertingDataForContext();
RunSomeActionToMakeSomethingHappen();
AssertThatSomeExpectedOutcomeOccured();
}
}
</code></pre>
<p>You could make this an abstract base class and make the SetUp and TearDown methods virtual if you would like to reuse this across any of your data test fixtures. As long as you don’t call _scope.Complete() the changes you have made should be rolled back/aborted on the disposal of the transaction.</p>
<p>Hope this helps!</p>
</body>
</html>Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-68421229711198622902014-01-20T17:29:00.000-06:002016-06-03T22:09:43.524-05:00New Blog Series<html>
<head>
<title>2014-01-20_new_blog_series</title>
<style>
/*
Name: GeekPark article style for Mou app
Author: hzlzh(hzlzh.dev@gmail.com)
URL: https://github.com/GeekPark/Doc/blob/master/GeekPark/GeekPark-Style-for-Mou.css
*/
body{ font-family:"Microsoft Yahei","Helvetica Neue","Luxi Sans","DejaVu Sans",Tahoma,"Hiragino Sans GB",STHeiti; font-size:14px; line-height:1.6; color:#666666; padding-top:10px; padding-bottom:10px; background-color:white; padding:30px; }
body > *:first-child{ margin-top:0 !important; }
body > *:last-child{ margin-bottom:0 !important; }
a{ color:#109EFF; text-decoration:none; }
a:hover{ border-bottom:1px dotted #109EFF; }
a:visited, a:active{ color:#109EFF; }
a.absent{ color:#cc0000; }
a.anchor{ display:block; padding-left:30px; margin-left:-30px; cursor:pointer; position:absolute; top:0; left:0; bottom:0; }
p a{ margin:0 2px; }
h1, h2, h3, h4, h5, h6{ color:#333333; margin:20px 0 10px; padding:0; font-weight:bold; -webkit-font-smoothing:antialiased; cursor:text; position:relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor{ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center; text-decoration:none; }
h1 tt, h1 code{ font-size:inherit; }
h2 tt, h2 code{ font-size:inherit; }
h3 tt, h3 code{ font-size:inherit; }
h4 tt, h4 code{ font-size:inherit; }
h5 tt, h5 code{ font-size:inherit; }
h6 tt, h6 code{ font-size:inherit; }
h1{ font-size:18px; font-weight:bold; line-height:22px; margin-bottom:5px; color:#333; }
h2{ font-size:16px; font-weight:bolder; line-height:18px; margin:20px 0; }
h3{ font-size:14px; }
h4{ color:#666; font-size:14px; font-weight:bolder; line-height:18px; margin:20px 0; }
h5{ font-size:14px; }
h6{ color:#777777; font-size:14px; }
p, blockquote, ul, ol, dl, li, table, pre{ margin:15px 0; line-height:150%; }
hr{ background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0; border:0 none; color:#cccccc; height:4px; padding:0; }
body > h2:first-child{ margin-top:0; padding-top:0; }
body > h1:first-child{ margin-top:0; padding-top:0; }
body > h1:first-child + h2{ margin-top:0; padding-top:0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child{ margin-top:0; padding-top:0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6{ margin-top:0; padding-top:0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p{ margin-top:0; }
li p.first{ display:inline-block; }
li{ font-size:14px; line-height:150%; margin-bottom:5px; margin-top:0; }
ul, ol{ padding-left:30px; }
ul :first-child, ol :first-child{ margin-top:0; }
dl{ padding:0; }
dl dt{ font-size:14px; font-weight:bold; font-style:italic; padding:0; margin:15px 0 5px; }
dl dt:first-child{ padding:0; }
dl dt > :first-child{ margin-top:0; }
dl dt > :last-child{ margin-bottom:0; }
dl dd{ margin:0 0 15px; padding:0 15px; }
dl dd > :first-child{ margin-top:0; }
dl dd > :last-child{ margin-bottom:0; }
blockquote{ background:url("data:image/png;base64,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") no-repeat scroll left 11px transparent; color:#999999; margin-left:28px; min-height:30px; padding:17px 40px 0; }
blockquote p{ color:#999999 !important; margin-bottom:25px !important; }
blockquote > :first-child{ margin-top:0; }
blockquote > :last-child{ margin-bottom:0; }
table{ padding:0; border-collapse:collapse; }
table tr{ border-top:1px solid #cccccc; background-color:white; margin:0; padding:0; }
table tr:nth-child(2n){ background-color:#f8f8f8; }
table tr th{ font-weight:bold; border:1px solid #cccccc; text-align:left; margin:0; padding:6px 13px; }
table tr td{ border:1px solid #cccccc; text-align:left; margin:0; padding:6px 13px; }
table tr th :first-child, table tr td :first-child{ margin-top:0; }
table tr th :last-child, table tr td :last-child{ margin-bottom:0; }
img{ border:1px solid #E1E1E1; margin:0 auto 10px; display:block; max-width:512px; padding:5px; }
span.frame{ display:block; overflow:hidden; }
span.frame > span{ border:1px solid #dddddd; display:block; float:left; overflow:hidden; margin:13px 0 0; padding:7px; width:auto; }
span.frame span img{ display:block; float:left; }
span.frame span span{ clear:both; color:#333333; display:block; padding:5px 0 0; }
span.align-center{ display:block; overflow:hidden; clear:both; }
span.align-center > span{ display:block; overflow:hidden; margin:13px auto 0; text-align:center; }
span.align-center span img{ margin:0 auto; text-align:center; }
span.align-right{ display:block; overflow:hidden; clear:both; }
span.align-right > span{ display:block; overflow:hidden; margin:13px 0 0; text-align:right; }
span.align-right span img{ margin:0; text-align:right; }
span.float-left{ display:block; margin-right:13px; overflow:hidden; float:left; }
span.float-left span{ margin:13px 0 0; }
span.float-right{ display:block; margin-left:13px; overflow:hidden; float:right; }
span.float-right > span{ display:block; overflow:hidden; margin:13px auto 0; text-align:right; }
code, tt{ margin:0 2px; padding:0 5px; white-space:nowrap; border:1px solid #eaeaea; background-color:#f8f8f8; border-radius:3px; }
pre code{ margin:0; padding:0; white-space:pre; border:none; background:transparent; }
.highlight pre{ background-color:#f8f8f8; border:1px solid #cccccc; font-size:13px; line-height:19px; overflow:auto; padding:6px 10px; border-radius:3px; }
pre{ background-color:#f8f8f8; border:1px solid #cccccc; font-size:13px; line-height:19px; overflow:auto; padding:6px 10px; border-radius:3px; }
pre code, pre tt{ background-color:transparent; border:none; }
@media screen and (min-width: 914px){
body{ width:854px; margin:0 auto; }
}
</style>
</head>
<body>
<figure>
<img alt="" src="https://raw.githubusercontent.com/toddmeinershagen/Blog/master/images/happy_new_year_banner.jpg" title="Happy New Year!" />
<figcaption></figcaption></figure>
As the new year is upon us, I have decided that I need to more consistently contribute to the community. And what better way to do that than to write more consistently on my blog. <br />
In order to produce something a few times every week, I have decided to explore the tools that I use every day in greater depth - to look further into the nooks and crannies and make sure that I truly understand the capabilities of the tools that I leverage. <br />
This idea came from the book, <strong>“The Passionate Programmer”</strong> by Chad Fowler. In it, he suggests that, <br />
<blockquote>
Our industry tends to practice on the job.<br />
</blockquote>
He then relates our craft to the art of playing music, and, <br />
<blockquote>
Musicians are paid to perform in public—not to practice. <br />
</blockquote>
So why would we expect to do it differently in our profession. <br />
<figure>
<img alt="" src="https://raw.githubusercontent.com/toddmeinershagen/Blog/master/images/musician_practicing.jpg" title="A Practicing Violinist" />
<figcaption></figcaption></figure>
It takes hours of practice in order to learn our craft and, unfortunately, too many are practicing on the job these days, because it is acceptable. You cannot learn everything that you ought to know as a software craftsman by merely writing code for production software. Focusing on certain aspects is needed in order to increase the quality and resilience of what we produce. <br />
One of the areas that musicians focus on developing is <strong>physical/coordination</strong> or focusing on fundamental technical aspects of playing an instrument. They do this by playing scales in all of the range of the instrument, building the muscles in their lips or gaining callouses in their fingers, practicing dynamics with their diaphragms, etc. They cannot always be playing nice sounding music - they have to play simple, focused, seemingly monotonous exercises to focus on these fundamentals.<br />
How can a software craftsman do the same? They can focus on looking at the full range of functionality available to them within a certain language, platform, or tool. And they can practice using these tools in private exercises known as katas or personal projects. That is what I seek to do with this series. <br />
For starters, you may not have noticed it, but I am writing this blog now entirely in markdown syntax. In this post, I learned the following:<br />
<ul>
<li><strong>Images</strong> - add an exclamation ‘!’ at the beginning, follow with brackets [alt text] with some alternate text, open parentheses (url “optional title”) with a url and a title in quotes, which is optional.</li>
<li><strong>Strong Emphasis</strong> - add two astericks ‘**’ or two underlines ‘__’ on both sides of a word/phrase to emphasize it in italics.</li>
<li><strong>Block Quotes</strong> - add a greater than sign ‘>’ to the left of each sentence and it will stand out as a quote.</li>
<li><strong>Unordered Lists</strong> - add an astericks ‘*’ before each line which is translated into an unordered list item in HTML.</li>
<li><strong>Inline Links</strong> - add brackets [text] including any text to display and follow up with parentheses (url “optional title”) with a url and optional title in quotes.</li>
</ul>
You can find out more about markdown syntax by looking at <strong><a href="http://daringfireball.net/projects/markdown/syntax#img">this post</a></strong> from the Daring Fireball blog, which does a good job of explaining the basic features of markdown.<br />
Hope it helps!<br />
</body>
</html>Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-11558596150035229662013-08-15T19:16:00.001-05:002013-08-15T19:37:39.009-05:00New Library for Non-Deterministic Testing<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">I have currently been working on creating a system-level, feature test for some functionality that our company is developing to allow hospitals and health care providers to request a batch of eligibility requests for patients using a combination of Visual Studio 2012, <a href="http://www.specflow.org/specflownew/" target="_blank">SpecFlow 1.8</a> and <a href="http://fluentassertions.codeplex.com/" target="_blank">FluentAssertions</a>. </span><br />
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;"><br /></span>
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">In doing so, I ran into the problem of non-deterministic time. </span><span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Once a user uploads a file of requests, there is not a determined amount of time for that request to get a response from a third-party provider that we use to fulfill the request. </span><br />
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;"><br /></span>
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">So how do we handle the fact that we need to make some assertions at the end of the upload? What would be nice would be to either retry assertions that fail or keep trying an assertion in the event of failure for a given timeout period. In this case, we need to know that we can get a response within 30 seconds.</span><br />
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;"><br /></span>
<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Enter <a href="https://github.com/toddmeinershagen/James.Testing" target="_blank">James.Testing</a>. (Check it out when you get a chance. You can download the dependency to your project from NuGet.org <a href="https://www.nuget.org/packages/James.Testing/" target="_blank">here</a>.)</span><br />
<br />
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
James.Testing is a library of test utilities named after the author who wrote the book of James in the Bible.</div>
<blockquote style="border-left-color: rgb(221, 221, 221); border-left-style: solid; border-left-width: 4px; color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin: 15px 0px; padding: 0px 15px;">
"Dear brothers and sisters, when troubles come your way, consider it an opportunity for great joy. For you know that when your faith is tested, your endurance has a chance to grow." <strong>(James 1:2-3)</strong></blockquote>
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
It's a fairly apt description of what testing ought to do for our applications as well.</div>
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
Below is a description of the supported features.</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 2em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a class="anchor" href="https://github.com/toddmeinershagen/James.Testing#action-extensions" name="action-extensions" style="bottom: 0px; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; position: absolute; text-decoration: none; top: 0px;"></a>Action Extensions</h2>
<h3 style="color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a class="anchor" href="https://github.com/toddmeinershagen/James.Testing#executing-an-action-with-retries" name="executing-an-action-with-retries" style="bottom: 0px; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; position: absolute; text-decoration: none; top: 0px;"></a>Executing an Action with Retries</h3>
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
Many times in integration tests, there is a non-deterministic time period between executing some initial action and asserting your expectations for the outcome. In this case, it would be nice to have a method for automatically having the test retry your action for a number of times even though the assertion fails. This method also supports setting a wait time in between retries so that you don't overload your system.</div>
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
<strong>Example:</strong></div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px;">var counter = 0;
Action action = () => counter++;
action.ExecuteWithRetries(times, waitTimeInSeconds);
</code></pre>
<h3 style="color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a class="anchor" href="https://github.com/toddmeinershagen/James.Testing#executing-an-action-with-a-timeout-period" name="executing-an-action-with-a-timeout-period" style="bottom: 0px; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; position: absolute; text-decoration: none; top: 0px;"></a>Executing an Action with a Timeout Period</h3>
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
In other cases, you might want to execute a given action for a given time period. For instance, if you have a requirement to expect a response within 30 seconds, you can set the maximum timeout period to 30 seconds for your assertions. This method also allows a user to set a given wait time between executions of a given action.</div>
<div style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px; margin-bottom: 15px; margin-top: 15px;">
<strong>Example:</strong></div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-top: 15px; overflow: auto; padding: 6px 10px;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px;">var counter = 0;
Action action = () => counter++;
action.ExecuteWithTimeout(timeoutInSeconds, waitTimeInSeconds);</code></pre>
Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-80318759075190373092012-10-05T16:59:00.001-05:002012-10-05T16:59:52.296-05:00Investigating a Build Configuration Change in TeamCity<p> </p> <p>Our team is using TeamCity to run our continuous integration and nightly builds for our current project. We discovered that in one of our build configurations, there was a build step that was no longer present, and we wanted to know who/what deleted it.</p> <p>After looking online without success, I found that TeamCity actually provides auditing for these kinds of activities out of the box. In order to find this information do the following:</p> <p>1. Click on the Administration link in the upper, right-hand corner of the TeamCity dashboard. (Yes – this requires administrator privileges for at least the project.)</p> <p>2. Click on the Audit link under the Project-related Settings section in the left-hand side of the screen. (Shown below)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHFlI1347a6jjdlDjk9jJbu8iEu59ebe5SRN2GlFk2512kF4Jj6TDiuLevG8d_nXWzUFYK_eU-aCbVCWkwigP4OCfmTvnl-EAqU0ElLfThE3d-c_US56IsPY2JCrDar7lT3VBEFSJVCJeN/s1600-h/image%25255B15%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtqyewzFDmiXBfkNrW3mamPvCUnOcQ5bWArf4PfJlCFfhdk2F9TO9GgG9FJOVS2YtnnYIhtz-j9VXu7XwJA88wwmvtkwgosOKM07nilDOVD8mXzeMqvsF2BaYOftk0dtPFktpayW_kFprh/?imgmax=800" width="598" height="78"></a></p> <p>3. Select desired filters above the results list. You can filter by action, build configuration, and user.</p> <p>4. In the list item in Step 2, you can actually click on the “view changes” link to see a comparison of the configurations in order to find out what has changed. Below is an example of a build step being disabled.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaKHo-SNUuDkbwFk4W28nCtOSxC6whs-kEsNvNO1nRTFEV9kWpqMFuyXCNW7J4e-hm_zPTQ71GGpCYbNiLK92EMa6Uyog38sgheoxX0NejZZVFbD_6jgV65VZ2UASGLL2L_pFm3yuaNqPY/s1600-h/image%25255B19%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1XWx_EByrWWoULnHLRszvyIdV0vodInTMKt_N_0QBtKkqrNeZPAqEBKHcrYzrgiJRj-fPtBxMdxzN1RurI7gsIuTBIm3jED5pxVZG6RAbCHDPrbKCj7XOy13Qmaog6n1o8w1rC9Y6IcRi/?imgmax=800" width="606" height="107"></a></p> <p>Hope this help.</p> Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-77359137822135584772012-01-23T21:24:00.003-06:002012-01-23T21:25:32.811-06:00AgileDotNet 2012My company, Improving, is hosting our third annual AgileDotNet conference in Dallas on Friday, February 17th. It will be a day of presentations and discussion focused on agile software development on the Microsoft stack, ALM tools, and the leadership and cultural issues involved in agile IT. Hope you can join us!<br />
<br />
Full details can be found <a href="http://www.agiledotnet.com/">here</a>.Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-4543566468583999162011-12-26T14:42:00.001-06:002012-01-02T13:41:33.786-06:00Using Gists for Code SnippetsNormally, I use Windows LiveWriter to write my blogs at <a href="http://www.blogspot.com/">BlogSpot</a>. And I have always used syntax highlighter plug-ins to insert code snippets. These utilities in the past inserted a lot of html elements and style definitions in-line with the rest of the post or required setting up global stylesheets and javascript in order to work.<br />
<div>
<br /></div>
<div>
In the last few weeks, as I have been looking at transitioning my blog to a ruby-based engine called <a href="http://www.octopress.org/">OctoPress</a>, I found another mechanism for inserting code snippets - <a href="http://gist.github.com/">gists</a> from <a href="http://www.github.com/">GitHub</a>. It allows you to store your code snippets online and easily add them to your posts with one line of code.</div>
<div>
<br /></div>
<div>
All you need to do is:</div>
<div>
<br /></div>
<div>
1. Go to http://gists.github.com</div>
<div>
<br /></div>
<div>
2. Sign up for a free GitHub account</div>
<div>
<br /></div>
<div>
All you have to do is click on the link in the upper, right-hand corner "Sign up for a GitHub account". It leads you through a process.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQb0E_m7lyLXEF1nM1dzI9YKeYrdbKLkF6ib7iacq8XyY381OPiolxz-Hof2apKLs3v_JfjXxi8njfknBeh1gNktEe15iVG4QoDxZQucGw-e4FoaTr-4Qju6sh69ItLlwSf2JcDZc2ReAl/s1600/Screen+Shot+2011-12-26+at+2.24.49+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="441" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQb0E_m7lyLXEF1nM1dzI9YKeYrdbKLkF6ib7iacq8XyY381OPiolxz-Hof2apKLs3v_JfjXxi8njfknBeh1gNktEe15iVG4QoDxZQucGw-e4FoaTr-4Qju6sh69ItLlwSf2JcDZc2ReAl/s640/Screen+Shot+2011-12-26+at+2.24.49+PM.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If you don't wish to create an account, you can create gists anonymously as well.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
3. Add gist to GitHub</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK-vGAfGxk24xrn_f1n1bSGHtVFE05ULsn15I0GtrBvrxLawWjFnkXd5-_m7dVGeONNpQsphqwqX9WVtpQR3lXcG1VU5LQoQuyqmfdT52d8pdE31dzXNkXw_TcT6NGP3D_JdaKgs4yEDsf/s1600/Screen+Shot+2011-12-26+at+2.26.43+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK-vGAfGxk24xrn_f1n1bSGHtVFE05ULsn15I0GtrBvrxLawWjFnkXd5-_m7dVGeONNpQsphqwqX9WVtpQR3lXcG1VU5LQoQuyqmfdT52d8pdE31dzXNkXw_TcT6NGP3D_JdaKgs4yEDsf/s640/Screen+Shot+2011-12-26+at+2.26.43+PM.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
All you need to do in order to add a new gist is: </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
a. Create a name for the gist</div>
<div class="separator" style="clear: both; text-align: left;">
b. Create a name for the file (this is optional)</div>
<div class="separator" style="clear: both; text-align: left;">
c. Select a language </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If you give the file a name, the system will determine what the language is from the extension.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
d. Put the text of the code snippet in the body of the gist</div>
<div class="separator" style="clear: both; text-align: left;">
e. Save the gist by clicking on the Save Gist button.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYx_0WvHhqs_FuCbhcXa_hQ0_ulLIuuGoZbqXWg9Atp7VQfk66WS-1JP4S2EdYFp9HqZF-GuxWZ6XgyTUbLJY6I9qYZofmGC_iUsEjkiJqxOkfaL8Iwqz2MxMcw0c9duS9_96Vi0ktWvUU/s1600/Screen+Shot+2011-12-26+at+2.26.23+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYx_0WvHhqs_FuCbhcXa_hQ0_ulLIuuGoZbqXWg9Atp7VQfk66WS-1JP4S2EdYFp9HqZF-GuxWZ6XgyTUbLJY6I9qYZofmGC_iUsEjkiJqxOkfaL8Iwqz2MxMcw0c9duS9_96Vi0ktWvUU/s640/Screen+Shot+2011-12-26+at+2.26.23+PM.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
4. Add the gist in your post</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In order to add the gist to your post, you will need to click on the show embed link and add the html snippet to the html content of your post. In this case, </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<script src="https://gist.github.com/1522062.js"> </script></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Once you have added this, the code should appear in the post as below.</div>
<br />
<script src="https://gist.github.com/1522037.js">
</script>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
5. Add line numbers via additional css styles</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You may notice once using the steps above that the native gists from GitHub do not support line numbers currently, so in order to add them I found a gist that contains the .css styles that you need to add to your blog site. Once added, all snippets appear with line numbers as you saw in point number 4. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<script src="https://gist.github.com/1243028.js">
</script>
<br />
<div>
If you find another way to do this by adjusting settings at GitHub, let me know in the comments. <br />
<br />
Hope this helps!</div>Todd Meinershagenhttp://www.blogger.com/profile/15973461415802595901noreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-46384405545958267362011-02-11T03:18:00.003-06:002012-01-02T14:25:38.329-06:00Creating Data-Driven Tests in MS TestFor my current client, I was looking for a way to create a data-driven unit test in MSTest. Basically, you can define a test once and then define a data source that provides multiple rows of data to be sent through the same test. That way, you don’t have to write redundant tests.<br />
I had done this previously, but I couldn’t remember how it was done. I’m writing this post in order to remind myself and hopefully help someone out there.<br />
1. Create a Test Method<br />
The first step is to make sure you have a test method. You can do this by making sure that in your test project you have at least one class decorated with the [TestClass] attribute and a method with the [TestMethod] attribute. <br />
<div class="csharpcode"><pre class="alt">[TestMethod]</pre><pre><span class="kwrd">public</span> <span class="kwrd">void</span> Add_when_two_numbers_returns_proper_result()</pre><pre class="alt">{</pre><pre></pre><pre class="alt">}</pre></div><br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><br />
<br />
When creating this test class, make sure to keep the TestContext property as it is defaulted. You will be using this when coding your test.<br />
<br />
<br />
<div class="csharpcode"><pre class="alt"><span class="kwrd">private</span> TestContext _testContext;</pre><pre> </pre><pre class="alt"><span class="rem">/// <summary></span></pre><pre><span class="rem">///Gets or sets the test context which provides</span></pre><pre class="alt"><span class="rem">///information about and functionality for the current test run.</span></pre><pre><span class="rem">///</summary></span></pre><pre class="alt"><span class="kwrd">public</span> TestContext TestContext</pre><pre>{</pre><pre class="alt">get</pre><pre>{</pre><pre class="alt"><span class="kwrd">return</span> _testContext;</pre><pre>}</pre><pre class="alt">set</pre><pre>{</pre><pre class="alt">_testContext = <span class="kwrd">value</span>;</pre><pre>}</pre><pre class="alt">}</pre></div><br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><br />
<br />
2. Add a Test Data File<br />
<br />
For the purposes of this explanation we will be using a simple .csv file (TestData.csv). Make sure to add a text file, preferably at the root of your project with that extension. In the file, you will want to add data. I have added three columns per row: Operand1, Operand2, and ExpectedValue which represents the expected result of adding the two operands together. You can add as many rows of data to check all of the boundary conditions that express your intentions for your unit test.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiTfQkVXgrNXI-XAUcnSja6xIti9RAAZJepdlc705nwYvGMjPnmLgdawTtDPOg1PnFhYbEN9WfNOV_dUDvfnKvZosqdqp6I9NdB9RQaySPQvq1OqYrVfYR93tpcK50QNZMuj1nVfJNTMM/s1600-h/image%5B66%5D.png"><img alt="image" border="0" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC7kxXvJcwAwxza6SL0thXwdBRthG6LuPfHyMhqE3A94HTcCdtfsjdEQPZBEJek3_qzp4wAxyt_vKVrhsEaaxpazwD3QU0s4bKm7iMd6mcdv7ZKKEg7eSpkaEvFdLS5nOhbPIbDxJnYD8/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="410" /></a><br />
<br />
Right-click on the file and select Properties to set the Build Action to Content and the Copy to Output Directory to Copy Always as shown below. This will ensure that the file is copied to the Bin folder when running your unit tests.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZQfekCILvQ12Q2GNytePn3CCgIf5AdjSMjYxMQhxV7bHmybtiYboiy1-OPhurQ2nIrb7OwQuIa43o2IMkWcrl4EM7_V80_W4RU0W19jDOFg7inIhYLDVouWKjkIZJvZjjl3C2RCB07uU/s1600-h/image%5B27%5D.png"><img alt="image" border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUkwIk9X8Dr3qRrpXTi8w6oAEPcCGmLs6lZEey72T00-bQyuTIiN5niguu9ARc3dnnAVya0EvhhRDQGGzqVYe3gPbf4JaPscTMVsQfvIjELawEjhm64408F_AkmvsOizKt1OG1MBxwZFQ/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="299" /></a><br />
<br />
3. Open the Test View from the Test menu.<br />
<br />
From the Test menu, select the Windows –> Test View option as shown below.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0Q6toFAV2IGIzGC20Z1Zd-IcjsEeYnammpZtZp4nPILJZurj5iA2xEbXcxuRCKsoC5aw-Pi1XDfN08X5oVDHfhd_s3Ceyfsd9pJATKPbUKdogwa4HaheCRff9NU1harX66nhBh2JSoAE/s1600-h/image%5B4%5D.png"><img alt="image" border="0" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaVGEcQYq85bNMhGLWM1tAVfqxwI2u8FCKL89NwK-DeAfr0r4qYTuxuwtEET2d3RKQXyt82FbqTD2PvBAuhvJYytgnxKjAUt4wdk7fpdatnFk7-5baN47t6eul50fM-aTPJ12zMoRKSKs/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="430" /></a><br />
<br />
Once you open the Test View, you should see a list of the test methods that are available. When a test is highlighted, you will see the properties for that particular test in the Properties pane as shown below. <br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG8DXH-gGOJLCyDJ3rDtAA3B217xxDpZTSB0uceGrCSQr5s0_ejGfNriNdWLt2GyB6oGdTbfvSirJn3m4ywSrmcVaaQv3aTC2oAIZSj7Zh2lUy39uoOnH7vHXT-DL7a7cJL0QpR-ybqiw/s1600-h/image%5B36%5D.png"><img alt="image" border="0" height="725" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikiNLwvlz6sIabkK0VhqlcLXd6rBD8_1tztC_4aJFdXA_WH5SeQG_jJREns2y6OO_QPmCcThzi_9UY7VCfBtbtt8AsioSbBZq0d9xgmCILnT7oUMTFqaa1sYs7s0NUDstGPoOiYNmYRJU/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="386" /></a><br />
<br />
4. Assign Test File as Test Data Source<br />
<br />
Find the row for Data Connection String in the Properties pane and click on the button to the far right with the ellipses (…). That should open the following dialog where you will be presented with an option to set up a database, csv file, or xml file.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8fN7NkikKuMl9c4vj2q2lSh-qmWtQJoxSIHrTatiRkSNJfAAo-Vl14Pg7irQ_KbU8KTlpJhEozWXlQ2mZKhqLag8TNyLbEq7Z9wvEuURYQ3y0DZqYNdbL6u-q7p91tC5ZvyPazIySBgc/s1600-h/image%5B17%5D.png"><img alt="image" border="0" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixdF2jHpmRVPdn2jf3NHOwWV9C1Yc_7k_zN3Bq_yHsAkcciQ5TdfpP9QSolonK-qqYm4zzRa6uICZxpuIxkDtN6X_05xisjQy8vSGdnrhOono-i38mSexnV-NpOewDo-a7iejfxL3gz58/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="378" /></a><br />
<br />
The database option should be self explanatory. It is like any other database connection, and the most popular option is to use a simple MS Access DB or SQL Express database that you can include with your project.<br />
<br />
The other two options are file based. The CSV file will be explained in further detail below. The main difference between a CSV and XML file is that you can have multiple test data sets in the XML file while only one set of data would be accessible for a CSV. So, if you need to set up data for multiple tests, you would need to maintain multiple files with the CSV option. In the XML option, you could just maintain one with multiple sections within the XML file.<br />
<br />
Select the CSV File option and click Next.<br />
<br />
5. Select Your CSV File<br />
<br />
At this point, you will be presented with a dialog to select a CSV file. Click on the (…) button and select the location of the text file that you created for your test.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv33rBxl-OKyvyIG5jdntXT1v07iy2_z8oQW7s-PL3op-Xpd8-IOzQF3QK9z0qm-OmxnXAY5QN_aUrdUuqgQCzgKZxEsFQeJFB7QJaFUjvyNpSKpO5GR2taj2Sm_eS556dWSg7AAORktA/s1600-h/image%5B40%5D.png"><img alt="image" border="0" height="401" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNy_30iSJa1nEfyCIBg64IwiAabEzTzhAIpPpD2UEMjMrzgsbLSuGpj8I_b1o64PJzuXPeJZlewifTaY1MLqI4DKwps7LNZ9Lli4xWs_2Skz2qD1aTnt1jErhlwXlNrNBVRnYqk7tpENw/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="433" /></a><br />
<br />
Once selected, the dialog will show the contents of your CSV file as a data grid to allow you to examine the contents to make sure that the data is what you were expecting.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEnrfYXFpHG6SzqoqBNpkSg9Oqy2vsbFpLEQVRAIotQy4qkz1yYP9YA4rZVKesyzeyEx85mHi-mOM8DL3Kri0ykemQhIm3akZTP0l8pKPoH6CWHoQy7I-50GbTvR05OfMdszJ8eLQULz8/s1600-h/image%5B70%5D.png"><img alt="image" border="0" height="381" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqb5nU0lrqv9KQKz15ErmpAhoSfqZXzCAVpVb3xWe19JBxXU7j-Ie54yStEdBPBxdnnlgHOyXLp7Tc_zJ5krlPwsKrKZmfEFiY3a6tMoROVKZh0mahoAKoNWyTXUSaB3b-Umnutr9a9lQ/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="413" /></a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Click the Finish button once you have confirmed the file contents. You will notice that the properties have been updated to reflect the change.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd_PD28siFsLBYWPlHImWHW3FFwxRtXLuu9KocQw1wn-bFWm7_zMnvuxNxdXLP69M2DJrk_-DpbGEL3CxM4kpIw2sg5NuYBzqdGQ288Tcea99p5CYND1fQkpCDQLRiFeH1twAKHUvFcEA/s1600-h/image%5B49%5D.png"><img alt="image" border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUtZYuJzYxyFkicV51zmBML02Hxittv6ZQ7A0WSfG010CzTvjXTAKTAcYeugmD7FxuhLuI6_9Mp90ok1zNCj-SpWgzUMQZZ5CDN77p6Z6vzymSCI1L-IjiTRqWIXoabV8AnmEIr33VJlU/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="430" /></a><br />
<br />
In addition, Visual Studio will add a [DataSource] and [DeploymentItem] attributes to your original test method as shown below with the same information. In the future, you can set these attributes up on a test without needing to use the Properties wizard for selecting a Data Source.<br />
<br />
<div class="csharpcode"><pre class="alt">[DataSource(<span class="str">"Microsoft.VisualStudio.TestTools.DataSource.CSV"</span>, <span class="str">"|DataDirectory|\\TestData.csv"</span>, <span class="str">"TestData#csv"</span>, DataAccessMethod.Sequential), DeploymentItem(<span class="str">"Demo.DataDrivenTests\\TestData.csv"</span>), DeploymentItem(<span class="str">"TestData.csv"</span>), TestMethod]</pre><pre><span class="kwrd">public</span> <span class="kwrd">void</span> Add_when_two_numbers_returns_proper_result()</pre><pre class="alt">{</pre><pre></pre><pre class="alt">}</pre></div><br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><br />
<br />
<br />
6. Add Code to Reference Data Source<br />
<br />
Once you have added your test data to the test method, you will want to access it within the body of your unit test method. This can be done by referencing the DataRow property of the TestContext class-level variable. I have created a simple test to use the values to assert that the Add method of a simple Calculator class works as shown below. Because a DataRow column returns an object, you will need to do some casting to the appropriate data types.<br />
<br />
<div class="csharpcode"><pre class="alt">[DeploymentItem(<span class="str">"Demo.DataDrivenTests\\TestData.csv"</span>), DeploymentItem(<span class="str">"TestData.csv"</span>), DataSource(<span class="str">"Microsoft.VisualStudio.TestTools.DataSource.CSV"</span>, <span class="str">"|DataDirectory|\\TestData.csv"</span>, <span class="str">"TestData#csv"</span>, DataAccessMethod.Sequential), TestMethod]</pre><pre><span class="kwrd">public</span> <span class="kwrd">void</span> Add_when_two_numbers_returns_proper_result()</pre><pre class="alt">{</pre><pre><span class="rem">//arrange</span></pre><pre class="alt">var operand1 = System.Convert.ToInt32(TestContext.DataRow[<span class="str">"Operand1"</span>]);</pre><pre>var operand2 = System.Convert.ToInt32(TestContext.DataRow[<span class="str">"Operand2"</span>]);</pre><pre class="alt"></pre><pre>var sut = <span class="kwrd">new</span> Calculator();</pre><pre class="alt"> </pre><pre><span class="rem">//act</span></pre><pre class="alt">var result = sut.Add(operand1, operand2);</pre><pre> </pre><pre class="alt"><span class="rem">//assert</span></pre><pre>var expectedValue = System.Convert.ToInt32(TestContext.DataRow[<span class="str">"ExpectedValue"</span>]);</pre><pre class="alt"></pre><pre>Assert.AreEqual(expectedValue, result);</pre><pre class="alt">}</pre></div><br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><br />
<br />
7. Run the Test<br />
<br />
You can run the test as you would any other in MS Test. The result will look similar to other tests.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMY53jlbug6fKPIW_WYjNZkdFhX11hQykLkRLuZ9Ho9Dm_MG_gGuWJeCX5kK51ZnTfGUHv0biQ3LQkpi1fx2rUTufMwMafH6rlFS6MlVH8Yo4WxxcE841BPTizwylhrwMCaD21QphNFFs/s1600-h/image%5B53%5D.png"><img alt="image" border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicYCa5JzZr5U-tyMMnmgbx5nIRg9ZLsLQVwbrt8JCHURE50CbJ-MiGJn7sspEQrTY3HYCE_1GVEGOWHV8PXIqOTCGGOl_V1GjrDa56G2LruiDs5eLIwUw00rBpGXCscaLQ5MFMDTL8MyU/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="380" /></a><br />
<br />
However, if you right-click on the result row in the Test Results pane, and select View Test Results Details as shown below…<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5XTnVC5piITfwlg3_pbWJuH0biFzzrLE6YaWli_s_nienOBDhoAVc1b8m5NovuELjFQgWtDcTrIM48osbTqLSCOHqg6QNeDyLMe3Eyc5nEjQjlZKfsH0Y8EzqpXmRcKdugQVLhOLl5Kw/s1600-h/image%5B57%5D.png"><img alt="image" border="0" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4xZIq_3D6hYqAa6fr-WgjZhWla4CSFBtDOS_XRLkjd6ZISC38jyliRTNvhjDWlC6FTgzKtbb_o1PA0EitBA-psATX0nrK5-J7knK23S16If6cBJoDPGRkGG3TdwstsF0E7yaQgghBg-I/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="356" /></a><br />
<br />
<br />
<br />
<br />
…you will see the detail of the results to see which data combinations failed and why.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5TmFu_HFi6jQDecfi4qyDigYFPDpfmkrpbZmAz472mbFCl_Y7ZOehftrVgSSglsK0nzTkelsCv4xbmBTD-Qrpq9F5LMZgrED2lhsyXqZ_34fiQt5rNIp-3btGhB_bUM4yLLZpe5BgwcQ/s1600-h/image%5B62%5D.png"><img alt="image" border="0" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtgIvi5mAUt1WNdZScB-MadKyZGZ-5cCjvw1OmC1ammUXE02oziyJ1dvIkZSngFOclKKeM9JeyC9Qd4PQLIs19TT0uton79mrAUXz4ZCpq5U_Zir8velNohgNq7kDhh8Mzejswmh81V0k/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="397" /></a><br />
<br />
Hope this helps someone else out there.<br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-61584949101939844102010-09-30T22:35:00.003-05:002012-01-02T14:26:10.430-06:00Create Custom Test Category Attributes in Visual StudioIn the past, for each class library project we create in Visual Studio, we have maintained separate unit test and integration test projects. This has allowed us to easily configure continuous integration with TFS to run a given project’s unit tests on check-in and run the full suite of unit and integration tests on a nightly build.<br />
With the introduction of Visual Studio 2010, build types now can filter tests based on test categories. <br />
<br />
For example, I can categorize a given test as a unit test by doing the following:<br />
<br />
<span style="font-family: COnsolas;">[TestClass] <br />
public class Test <br />
{ <br />
[TestMethod] <br />
[TestCategory("UnitTest")] <br />
public void IsValid_returns_false_when_quantity_large() <br />
{ <br />
} <br />
}</span><br />
<span style="font-family: COnsolas;"><br />
</span><br />
This allows us to consolidate all tests into one project and distinguish by categories. The only issue is that these categories are based on strings that the developer must type, and this can create inconsistencies using magic strings which may not be noticed during the course of development.<br />
<br />
In order to get around this, another option is to create your own custom test category attributes that return the proper string. Microsoft has provided a base class, TestCategoryBaseAttribute for this very purpose.<br />
<br />
<span style="font-family: Consolas;">public class UnitTestAttribute : TestCategoryBaseAttribute <br />
{ <br />
public UnitTestAttribute() <br />
{} </span><br />
<span style="font-family: Consolas;"> public override IList<string> TestCategories <br />
{ <br />
get { return new List<string> {"UnitTest"}; } <br />
} <br />
}</span><br />
<br />
By overriding the TestCategories property, you can return the appropriate string(s) that represent this classification. In this case, we are returning the same string that the previous test category provided.<br />
<br />
In order to use this attribute, you merely need to add it to a given test method like so.<br />
<br />
<span style="font-family: Consolas;">[TestClass] <br />
public class Test <br />
{ <br />
[TestMethod] <br />
[UnitTest] <br />
public void IsValid_returns_false_when_quantity_large() <br />
{ <br />
} <br />
}</span><br />
<br />
With this kind of flexibility, if you had a limited list of attributes that you wanted to provide to developers, you could also create an enum type and pass that into the constructor of the custom test category attribute. <br />
<br />
Just create an enum type.<br />
<br />
<span style="font-family: Consolas;">public enum Category : int <br />
{ <br />
UnitTest = 0, <br />
IntegrationTest = 1 <br />
}</span><br />
<br />
Then, create the attribute using the enum as a constructor parameter.<br />
<br />
<span style="font-family: Consolas;">public class TestCategoryAttribute </span><span style="font-family: Consolas;">: TestCategoryBaseAttribute <br />
{ <br />
private TestCategory _category; </span><br />
<span style="font-family: Consolas;"> </span><br />
<span style="font-family: Consolas;"> public TestCategoryAttribute(TestCategory category) <br />
{ <br />
_category = category; <br />
} </span><br />
<span style="font-family: Consolas;"> </span><br />
<span style="font-family: Consolas;"> public override IList<string> TestCategories <br />
{ <br />
get <br />
{ <br />
var value = Enum.GetName(typeof (TestCategory), _category); <br />
return new List<string>{ value }; <br />
} <br />
} <br />
}</span><br />
<span style="font-family: Consolas;"><br />
</span><br />
To use the new attribute, you would do the following.<br />
<br />
<span style="font-family: Consolas;">[TestClass] <br />
public class Test <br />
{ <br />
[TestMethod] <br />
[TestCategory(Category.UnitTest)] <br />
public void IsValid_returns_false_when_quantity_large() <br />
{ <br />
} <br />
}</span><br />
<br />
Hope this helps!<br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-33865612409041776312010-08-23T22:21:00.001-05:002012-01-02T14:26:21.841-06:00Six Interview Questions for Agile TeamsI was reading through my blogs tonight and came across <a href="http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=16277&tth=DYN&tt=siteemail&iDyn=2" target="_blank">one</a> that did a nice job of explaining the qualities that an agile team member should possess. In addition, the writer included a good behavioral interview question for each.<br />
I briefly share each below, but I highly recommend reading the <a href="http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=COL&ObjectId=16277&tth=DYN&tt=siteemail&iDyn=2" target="_blank">original article</a>.<br />
1. <u>People Who Collaborate</u><br />
<em>"Think back to a recent project. Give me an example of a time you had to work with other people to make sure that you could finish something. What happened?"</em> <br />
2. <u>People Who Ask for Help</u><br />
<em>"Think back to your most recent project. Tell me about a time you did not understand something. What did you do?" </em><br />
3. <u>People Who are Willing to Take Small Steps and Get Feedback</u><br />
<em>"When you work on your projects outside of work, how do you work?"</em> <br />
4. <u>People Who are Willing To Do Something That is Good Enough for Now</u><br />
<em>"Tell me about a recent time you did not know everything at the beginning of the project. What did you do?"</em> <br />
5. <u>Adaptable People</u><br />
<em>"Tell me about a time when you did not have the conditions you would've liked for your project. What did you do?"</em> <br />
6. <u>People Willing to Work Outside Their Expertise</u><br />
<em>"Tell me about a time you took on work to help the team. What was that like?"</em> <br />
So, tell me dear Reader – what questions do you ask when interviewing candidates for an agile-oriented team?<br />
<br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-55191021757309170812010-05-29T07:30:00.000-05:002012-01-02T14:26:53.488-06:00MotivationsI found this <a href="http://lifehacker.com/5550373/the-surprising-realities-behind-what-motivates-us-in-illustrated-form">video</a> about what motivates people to be very refreshing. Basically, if the tasks that people are working on require more than a basic physical action, money rewards don't motivate, but rather demotivate people. What really motivates others to perform well at conceptual tasks are three things: autonomy, self mastery, and purpose. What I find is that Agile practices tend to foster or work within these motivations. <div><br />
</div><div>For example, user stories really help to zero in on the purpose for a given feature request. "As a [actor], I can [do something], so that I can [accomplish a goal]." Developers really get a sense for why they are building a piece of functionality rather than just focusing on building a method, etc. And the prioritization of these stories helps to clarify what is truly important within a sprint.</div><div><br />
</div><div>As well, agile practices promote mastery by emphasizing continual improvement. Teams are encouraged to use the processes that work for an individual team rather than trying to create a process that will work for an entire organization. Other principles such as refactoring and unit testing also suggest an intense focus on continually improving the code base.</div><div><br />
</div><div>And finally, the scrum meeting and agile planning in general focus on the team working together on deciding the priorities rather than having a central authority such as a PM do that. Individuals make themselves accountable to the team by explaining what they accomplished yesterday and what they plan to accomplish for the current day. This creates a sense of autonomy in those performing the work.</div><div><br />
</div><div>I would be interested to hear your thoughts on the video as well as whether or not you agree that agile practices help to foster these motivations. </div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-8934496855420605482009-11-29T15:47:00.003-06:002009-11-29T15:52:34.322-06:00Rick Warren Speaks on Meet the Press - GivingI really enjoyed seeing Rick Warren, the pastor of Saddleback Church in California, speak on giving on Meet the Press with David Gregory. (below)<div><br /></div><div>And what influence he has - not just because he has a platform on national television, but because he actually gives 90% of his income. He has the authority to speak on this subject!<br /><br /><div><iframe height="339" width="425" src="http://www.msnbc.msn.com/id/22425001/vp/34193069#34193069" frameborder="0" scrolling="no"></iframe><p style="font-size:11px; font-family:Arial, Helvetica, sans-serif; color: #999; margin-top: 5px; background: transparent; text-align: center; width: 425px;">Visit msnbc.com for <a style="text-decoration:none !important; border-bottom: 1px dotted #999 !important; font-weight:normal !important; height: 13px; color:#5799DB !important;" href="http://www.msnbc.msn.com/">Breaking News</a>, <a href="http://www.msnbc.msn.com/id/3032507" style="text-decoration:none !important; border-bottom: 1px dotted #999 !important; font-weight:normal !important; height: 13px; color:#5799DB !important;">World News</a>, and <a href="http://www.msnbc.msn.com/id/3032072" style="text-decoration:none !important; border-bottom: 1px dotted #999 !important; font-weight:normal !important; height: 13px; color:#5799DB !important;">News about the Economy</a></p></div></div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-36267208552705197032009-09-05T02:54:00.001-05:002009-09-05T02:54:44.054-05:00Static Code Analysis - Part 2<p>In my last post, I showed how you could enable static code analysis for a visual studio project.  However, you can also set up static code analysis at a more global level if you are using Team Foundation Server for source code control.</p> <p>Within a Team Project, you can set up a check-in policy that requires the code to pass static code analysis.  You can do this by simply right-clicking on the Team Project and selecting Source Control from the Team Project Settings.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIqEPqWUgyhyphenhyphen7fSujuy4E4pXyk_OVMuqURL6j-vciPKjAx_PQ_BVyKu5FpNZCFj9NZyKD119BXXLPbsRy-qJy3SuXieeq0dab1e9lXe8JGvh6GV261tM7lEtKKaZmjjBaMBNz31hXyoYc/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="232" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOp1xi1cA4CcaadDfBUXgHd_6C-g76fhhqukH_oy2x_xVqlrgff9oa0_WViy5dqb0Hu10zrHtwOLsWP3lnSaVXIeW4DqQOuhN0Xfw3Hc9ksFQpW_8kcoEf11xCU_0nrjv18D8HZ30kjcw/" width="370" border="0" /></a></p> <p>From the Source Control Settings dialog, click on the Check-In Policy tab. and click the Add... button.  (Note - I already have the Code Analysis policy set for my project in the image below.)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDMyApmP88bNMJ_PotM0eQBgDunH28pwOtdZcU2BVBMnvVVQnpixkj5k0uTm1-bGBTLIh3Z8dSCkuqzUH-ReSbnkbCPsvKqxyQS1aRLLGt30KXhr6saVWiSIx4SEZUaTPNFSHDConbqE0/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="167" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj184IBTrJy2vf0IgD62F_QQC0Z0YIojIOSW8N3vz1dhyRAAaSS0Y48TQS9WI8JOqlxJ16iTFl6vMK47N7A7xwBHJ3XqbUBrwdUos58L1ka51c8wMkmrB4B9ayP3bssB5HUM3n9DP-CFvw/" width="395" border="0" /></a>  </p> <p>Click the Add... button to add a new check-in policy and select Code Analysis from the menu.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgirIkrbuvtWPUfaTUAL7nz9-Y_BU6RyTdB4X59vONP9MUYNq6WP1tgndeu3plfRsMG8-3LCvDestRvhyx5tejkXExDehSeQJlUwBORhf79jfL9ENXsFI6BrooN5yfO2MGGYbJUplKMwWk/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="228" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9gjMk1b1D-thSQdTLAHOf4IERA3r9ncFcs58Ls8vXk2_opd5Vapz71UlHYKCOI4xJr_Yygql4exvAljNN4vk8YCDxSHslHsZqhX_8ODm-EkVjkN3EmAGsFUGZ20LSMPSCAP0gdygiUgA/" width="334" border="0" /></a> </p> <p>From here, you should be able set up the rules just as you would at the project level.  Any rules you specify should generate an error when violated, and therefore, the code will not compile.  As a result, the developers will not be able to check-in code that violates any of the rules that you have set for the team.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg664dKmDXDkX1pja_tohYVdN_AGC-Fu275sNKKvoz2TQ_vmoTQnrvi8Y__g-0gZcJq0wXVGeyFU5ycDFxjMO4QjTMfYp30NE-vGhdpV4fimCDRoRWQzXMuFbH69FKlLzhjdztgeNmgMRA/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="352" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpDUJ7UZDbZqrhhde2asot40jPLvsrfXMBrgldPMd-iiubGC7SDB5gnPhMe44J4GecHBbTQWpmE6BzhozdjzapPit8IL29O_-amRZyuhdXNNVBqNumsGvHWEixGu7vnjznvmWV6031Yso/" width="308" border="0" /></a> </p> <p>So, if you have already set up rules within your projects, another nice feature in Visual Studio is the ability to synch up your settings in each project with those set at the check-in policy level.  You can do this by selecting the Replace with Check-in Policy under Analyze/Code Analysis Settings for Solution in Visual Studio.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidIDNJ1qMRW1kU5txN_TJ-9XDblj_gfzPVROWY1mUM_eVe5TrpvYIUzDfc3_npTUKAbzRPqaBRyteuvUMewDdn1C7LJ4oIQopo8oj0p3tFa2zM70JoNsv02nae1PmoG_lziMdmDzKjNy4/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="167" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggsv2IzrlnSSEpShDll7vXSLXtpovTayQWF2WeVVrtr6773r4z8C3svG4nak-KEb3XJjBqlCSptKXU9Y9HCl-2ZxPkpgKaEd5qCSPSQ2_mpkFQt3QarJz69F-9g2Hv3RbvbzCJVXETtg4/" width="370" border="0" /></a> </p> <p>All of the settings in your current projects will match those set at the Team Project level.  None of your previous suppressions attributes should have been removed.</p> <p>Hope this helps!</p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-51193700896277147872009-09-05T02:22:00.001-05:002009-09-05T02:39:50.578-05:00Static Code Analysis - Part 1<p>The static code analysis within Visual Studio is a great way of automating initial code review.  In order to turn it on do the following.</p> <p>1.  Go to Properties within the particular project.</p> <p>Code analysis can only be enabled at the project level, so the first step is to go to your properties section of each project you want enabled for code analysis.</p> <p>2.  Go to the Code Analysis tab.</p> <p>3.  At the top, check the box that "Enable Code Analysis on Build..."</p> <p>4.  On the right-hand side of the screen, check the box for those rules that you want treated as an error.  (By default it is treated as a warning and will not stop the build process.)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDVdYGQk37OakqJJX2MW-3LLCQJjmq6J1-ZDp-Axvh5FrxprU6nO7mxInpB1V3bdfOlsupmms-JG2hcSCiN79rXKrKBY2Gn8TLLtlJsJ3WBY19pQA1PCdDrQAXCj-MRNrOUWpfBnqGb7w/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="137" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEgV5fTsfcLsJY5bLupF7bkRy1V6bv-Ni7r2cG63SKQKrDUG4SBSt91zxdVzBNQhyphenhyphen_FZZ5VOfVWaENnnVNEUjAZTom3kfuZQgQh3zYdtAJOCId63scN6GplAVQOYEgUj9jncGZFtu2SiM/" width="464" border="0" /></a> </p> <p>Sometimes the rules may not make sense for projects where a lot of code is auto-generated.  In this case, you could leave that rule as a warning in the project settings.  </p> <p>In other cases, you may want to suppress the errors for particular members of your types or for whole namespaces.  This can be done by right-clicking on the rule violation in the Error List that appears when compiling your project and selecting a Suppress Message option.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjJnmM_AcPUcP4ieIERVIxkeqzvaLosnY791FyISgRC9AoooBrQ2a75g1ATZDPw9i5E3ODpAk8Q3zETvxI14XZbaFA9a6_fNynZyAp08IlAc-P-iQdKwHzB0HGLm2-EzPbgENJjUCChjc/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="237" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaYxJFl0niPtuYa5LCCxk8Wq92kXknl4EZreGhhZlXIPKBHJoEhX9Kk2o4G-DHpmwXcp4F1CL8nk2foKIOMlz3a6ToGvTW1OM3ajhlmQrCWVwoB7Xt2VhcHnQXjNbW_E2XiQQzNCpjRUc/" width="452" border="0" /></a></p> <p>As seen above, this can either be set within your source or in a project suppression file.  You can learn more about this <a href="http://blogs.msdn.com/fxcop/archive/2006/12/28/FAQ-What-is-the-GlobalSuppressions.cs-GlobalSuppressions.vb-file-and-why-is-it-needed-Is-it-possible-to-change-the-name-of-this-file-David-Kean.aspx">here</a>. </p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-81648767888857927682009-04-17T12:12:00.002-05:002009-04-17T12:16:14.413-05:00JSON Serialization in .NET<p>Many of you may be familiar with the use of JSON (JavaScript Object Notation). It is a very tight syntax for expressing the state of an object and is very widely used in Web 2.0/AJAX style development in which objects are passed back and forth between the client using the XmlHttpRequest object out of band to eliminate the need to do a full page refresh.</p> <p>I found a great article by Rick Strahl that outlines the pros/cons of two built-in .NET serializers: JavaScriptSerializer and DataContractJsonSerializer. You can read about them <a href="http://west-wind.net/Weblog/ShowPost.aspx?id=442969" target="_blank">here</a>.</p> <p>After using both methods in my own application, I found that another con of the JavaScriptSerializer that is a pro for the DataContractJsonSerializer class is that it requires a public default, parameter-less constructor. This means that I cannot serialize objects that I also would like to make read-only, and therefore, requires a constructor with the properties defined up front.</p> <p>One point I wanted to make in this post was that the extension class that Rick defines in his post for simplifying DataContractJsonSerializer usage does not work properly. In order to correct it, I added the 'this' keyword to the first parameter so that .NET recognized the static methods as extensions to the object type. In addition, I converted the FromJsonString() method to a generic FromJsonString<T>() method to allow the return object to be strongly typed. </p> <p>Code is listed below, if you are interested.</p> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2urqpsGPxfd0kcHOC2jAEiBtAysgK2cuNIaaRCSUzNRHl5s1Rt3L2lW0z_blnMNlCxB7l3rGure0q9gs8F5xaCFyGO3GkufidNgbE6G6mliPyE8cc8IYofdK1vgj-IGEaPPlYf-50t6I/"><img style="border: 0px none ;" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTUQh-aF8BZxuSGMoRzTZsKY4UwPSHi-w7n1BBkw6y_mvdauyXtyRQdz4EN6kC3nRBb-FWim8YlxdE-3pGvhd8K4b8d4hpKo4GZngWG6ibSdvmCUWi7sVbYsOP0i0SO-hWxgSLIEeBqUk/" border="0" height="441" width="473" /></a>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-90090760836039410812009-04-15T21:18:00.001-05:002009-04-15T21:18:15.731-05:00Changing the Default Browser in Visual Studio 2008 with ASP.NET MVC<p>How frustrating!  I spent at least 15 minutes trying to figure out how to change the default browser for debugging to my preferred browser in Visual Studio 2008.  </p> <p>Apparently, with a normal ASP.NET application, you can just right-click on any .aspx file and select 'Browse With...' from the context menu.  The dialog that opens (shown below) has the option to select a browser and click 'Set as Default' button.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-lz5-IDYXO-Av8ZZm_ofFoLcKWJ2XUgo_mugjpBoNjCFrO5Q5ygQktaZ_vY7kqopOpWuTrF0LLNxnQiYMgoM_-GTA8S6z4qI6pJawU8Pz-8xOiVMa4gsgmBinn0g6diG7V2wqyE4mf_E/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="270" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwpAiSaGcI7RBB8nJpSfwkLjLdN3iuRo3IjmU-oZ6OgLEJYu7v2OeBGaR1qkEofoRmZ2O46JY7_RcX4m3c1tCISmkN0qwPVqzASgTUblSZYCvjXcpapB0VKQpzIDE_YZrqAPZWYpERfdg/" width="344" border="0" /></a> </p> <p>Unfortunately, the .aspx files in ASP.NET MVC applications don't don't provide this option in the context menu.  The only one that works is the Default.aspx file.  </p> <p>I found the answer from this helpful blog <a href="http://www.geeksandgurus.com/blogs/sjb/2009/03/how-to-change-default-browser-in-visual.html" target="_blank">post</a>.  Thank you, Steve Bodnar!  </p> <p>My recommendation to Microsoft is to either put this setting in the Tools/Options menu, which seems to be the most natural place to look for this setting, or place it in the Properties of the Web Site/Application project - which might be even better if you want to specify this setting per project.</p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-9150213631452356612009-03-11T19:36:00.001-05:002009-03-11T19:36:00.983-05:00Transparency is a Core Value in Work/Life<p>I am working on a current project where we are trying to create a site that gives visibility/transparency into our company and its performance whether good or bad.  This is being done in order to build relationship with those we do business with.  And it occurred to me how fundamental transparency really is in work and life.  </p> <p>Lately, I have noticed a lot of examples of people and processes that are geared to pursuing transparency.  Regardless of what I think of President Obama's policies, I have to say that he has been fairly transparent with his decisions and agenda.  And every time some corruption (financial industry, legislative pork) or misbehavior is mentioned, his solution tends to be creating some framework (site or process) for exposing those ills through transparency.</p> <p>It also occurred to me that a lot of project management processes aid us in exposing the truth about projects.  Risk management helps to expose potential issues that can ruin a project's timeline or budget.  Issues lists keep track of potential flaws in a given system.  And project post-mortems can help teams to learn from past mistakes and improve for future iterations.  </p> <p>Even rating systems within eBay and Amazon or content updates from Facebook can help to bring a level of transparency that build trust.</p> <p>So, why should transparency be so important?  </p> <p>For one, transparency <em><strong>builds trust</strong>.  </em>If someone knows the truth about me, whether good or bad, they can begin to expect certain behaviors from me.  They can trust that I am who I say I am, and there is no fear that I will change or that there is something they do not know about me.</p> <p>All relationships grow from a root of trust.  Without it, there is no basis for relationship.  So, if I want to grow quality relationships with my family, friends, and colleagues, I have to nurture trust, and therefore transparency.</p> <p>It also creates a level of <strong><em>accountability</em></strong>.  If I am transparent about my life and work to myself and others, I am forced to face reality.  And even though reality is not always pretty, it can allow me to choose to pursue change.  Without it, I can safely live in denial and be complacent with the way things are.  And worse, if I keep things a secret, those failures may grow worse.  It was once said, "You are only as sick as your secrets." </p> <p>The Bible concurs with these benefits saying that, </p> <p><em>"If we say we have fellowship with him while we walk in darkness, we lie and do not practice the truth. 7 But if we walk in the light, as he is in the light, we have fellowship with one another, and the blood of Jesus his Son cleanses us from all sin."</em>  (1 John 1:6-7)</p> <p>You cannot have fellowship (relationship) with others and grow in your life without a level of transparency.</p> <p>So, I have decided that <strong>transparency</strong> or <strong>being transparent</strong> needs to be a core value for me.  And this blog post is my first attempt at admitting that I need to work on it.  I need to be willing to be honest to others about my life and work regardless of the consequences and be humble enough to apologize when I have failed or hurt someone.  It's the only way to have the quality relationships and integrity I desire.</p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-2087767890056239762009-03-03T10:04:00.001-06:002009-03-03T10:04:00.230-06:00Web Service Naming Conventions<p>I was reviewing an interface for a WCF web service today, and I began wondering about web service naming conventions.</p> <p>It is understood that a service should be a logical grouping of a set of functionality.  Therefore, if you have several pieces of functionality that center around a Project concept, then you should group them together under the name ProjectService.  </p> <p>So, the convention for service names is:</p> <ul> <li><strong>Casing:</strong>      Pascal case</li> <li><strong>Format:</strong>     [concept noun] + 'Service' to construct the name.) </li> <li><strong>Examples:</strong>  ProjectService, TaskService, PersonService, etc.</li> </ul> <p>When creating methods for a data service, though, should you restate the concept in the title?  In this case, you would use the following methods:  CreateProject(), UpdateProject(), GetProjectByID().  Isn't this already understood by the title of the web service?  So that you could say Create(), Update(), and GetByID() instead.  </p> <p>I propose no.</p> <p>The latter might make more sense in an object-oriented world where you are operating on the object itself.  However, a service is more like a manager class that operates on Project objects.  Also, theoretically speaking, each one of these functions can live on their own apart from any other functionality.  So, specifying the concept in the title of each method would make sense.  And finally, there might be functionality in this service for sub-objects such as Task that would not be substantial/independent enough to live on its own in a TaskService. </p> <p>In that case, it would be important to understand which type of object your Create(), Update(), and GetByID() are operating on.</p> <p>So, my recommendation for a data web service methods is:</p> <ol> <li><strong>Casing:</strong>      Pascal case</li> <li><strong>Format:</strong>     [operation] + [concept noun] + [optional extensions]</li> <li><strong>Examples: </strong> CreateProject(), UpdateProject(), GetProjectByID()</li> </ol> <p>What are your thoughts?  </p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-32181871467484443592009-01-27T11:49:00.001-06:002009-01-27T11:50:22.221-06:00Team Foundation Server - Identifying All File Changes<p>Within <strong>Visual Studio 2008</strong>, it is very easy to view the Team Foundation Server history of either a given file, project, or solution.  All you have to do is right-click on the particular item, select <strong>View History</strong> from the context menu, and you are presented with a list of changesets as shown below.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqR-btJMFgx67wzqlScaNyszv7hvhN7WvEdXdyz9GY13qVSKZh269OwKQtJjaasYRXnfaO1tKgcYlEehRIobMSVAv9kK6af-EY-JHGvDyxDm621qbJkRmD4teGHdzUyGh5O98hsgkzATQ/"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRf7p-cP9-oZ65H_JPRDTmRGSWsDVnh_BgxSUNg-MAtC_1fYSsi37232CvHpnhZcT8nhx7ro8DCtMNGoPKKep5DOtTYd4RZy4iVNl1A7umLR4_Tgtcj5prA9e8aE-Q8oF00UAVo5C-jWw/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="273" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC0KIQP9Ws8bIYJBfOH6SwxTyMkZxuBh8yaXduqkZiMXHUSKWBepWuS2Mp3cDFlLO7DEEDD-cAdHGAEWqmMirMRLVmCPA8TNsczVUj3pW1oKMjaI9m0Jeg6mSVIw5xd6adnJwewQT03zY/" width="164" align="left" border="0" /></a><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="207" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0dnw7HRlCUxB-TO7dYTPComiwL-LlkT4qczOsWM9m2kc84638t5kjBrgYxiFldkDOjU5Vd-wU1MQ4B4xgiQi9hhiYiAnTqA-vuogEQ6QNuhSv5kVPKqYCFhTwmJNxoszCg3ZGVHrYqM8/" width="285" border="0" /></a> </p> <p> </p> <p> </p> <p>From there you can double-click on a given changeset and see the files that were a part of that atomic check-in.</p> <p>But how do you see a consolidated list of all files that have been modified since a particular date, label, or changeset?  That is a little less intuitive.</p> <p>The first step is to open the <strong>Source Control Explorer</strong> from the <strong>Team Explorer</strong> client window of <strong>Visual Studio</strong> by double-clicking on the <strong>Source Control Explorer</strong> node in the tree as shown below.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_48i1tJ9nAgNpUWrnloZw_iX8P4oxxU4wYgvsEXXXhDC4ICqgPGXVfY6RExzNEh5NwRC5L0Krz0xCZb-U4WvP9n6FZgYOO_xvoNHDUiy1hxFkFMV9Tmv9S8Hsy5UZF6tg45SIn6poecw/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="180" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSRP2mkAzasc_GuWJjCRXaeWO7pPAysNHqlgBJsSddhlhLzN6XU2lt7EtHLlWbFXqerFljv80VPV32DWVpbpb0C6lM92qb-kQR2tfkA_K-rA6LXfQwYg06Cbe8Q6TrxZsd5THNwsX1BZQ/" width="155" border="0" /></a> </p> <p>From the <strong>Source Control Explorer</strong> window, select the node within the project (either Team Project, Solution, Project, or file) and right-click to select <strong>Compare</strong>.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs5qOIEOYSHmUpQZvCx85C-mitpdypbRGJfKGCzHJw5d39dqjv66RSjLeV2y6GyaGa9fFhOHV1uTbPGXE_aBtO-UhEOHYFEfQM6DJ5xQhsnBv2QQWranbzMBHjMl2jbiD4Ee_i_pyL-sE/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="229" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPpGzh4Rs1I5USOkdHrAe00IllmdYlLhO9I_rQvE66AQ8u3tjpN84o-xY1npvClaQDjBsIcFtUxjLHi4YT4g_zlJu7A1fYx3UsHY9Ghm_Y6tLUo-qnW9ES0hjzmD-MQ-MAj0frOtvzNz0/" width="205" border="0" /></a> </p> <p>From there you will be presented with the <strong>Compare</strong> dialog shown below.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg42aoVBaxawPS6gn64ABQPsYz4GuE8tVh0ggFhMTAPH6m5bb40AQZGWNZzMF-T-btwGc85D1KU5nHjQ8P5Vh3znJa6WvY4W5HHDcyfZXy8TdUJDSzTUSZYD77FO8v1gGyU_ACW6-dfSTc/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="217" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4mYww0b1-4GlQIqaKRPecXCjxLBj6owrErZfjqrhBqI3qFoObv_sm5iaZ8YG0OZeapBf9zW9TC6UofyVb4vobS-DGDnM8lMMxJFNkqkJQIrFTR_SQOSz6v0qvib35sx0Y_QXNz95cbgI/" width="244" border="0" /></a> </p> <p>You can select to compare to a <strong>Changeset, Date, Label</strong>, etc. from the list.  For purposes of this article, we have selected the compare by <strong>Date</strong>.  Make sure that the only <strong>View Option</strong> selected in the checkboxes at the end of the dialog is "Show files that are different."  Once you click the <strong>OK</strong> button, you will be presented with the following window displaying all of the files that have changed, grouped by solution and project.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_8QRjyM3h_EfWK74hPqFuW2rRuhvaZp9NzVVQ-NuXNHdOU20b9aY7MqSrUhkHEPAmpIGeKTTD0WNbSfcTIPcC4NDlUP1cY8_U0BFCST7fC9NJyfA-ug6oVKwTXpB-egGrWD0I_SGltxc/"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="155" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtJWgBj1pxTIFj6AR8o2hhXuJ_XdALTlbTubTuRuzWsWrvktx8A2HkgWM_JT8MJ3Ie2rxBiyyu6MOPJXmKnk3WffM7dWtGupoqng7aYJIFBoB5YL9YzhTmBJG9Pek1OO41pCFzQDJ78cQ/" width="466" border="0" /></a> </p> <p>Hope this helps.</p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-87348536430595605852009-01-11T17:45:00.001-06:002009-01-11T17:47:25.653-06:00The Effective Executive - Part 1<p align="left"><a href="http://www.amazon.com/Effective-Executive-Definitive-Harperbusiness-Essentials/dp/0060833459/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1231717386&sr=8-1" target="_blank"><img height="188" src="http://ecx.images-amazon.com/images/I/51B7G1SKB0L._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg" width="188" align="right" /></a> So, I picked up a copy (used, by the way, from Amazon Marketplace for only $0.56 + shipping/handling) of <a href="http://www.amazon.com/Effective-Executive-Definitive-Harperbusiness-Essentials/dp/0060833459/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1231717386&sr=8-1" target="_blank">The Effective Executive</a> by Peter Drucker.  It is by no means a new book, being released in 1966, but it has some very valuable wisdom on how to effectively execute as a knowledge worker that is as relevant today as it was then.</p> <p>I am going to write several posts on the book, because I want to remember the important points from the book, and I would also like to share the most interesting portions with you.  This first post will be a quick intro to the book.</p> <p>The book is a mere 174 pages, but it takes time to read and digest the content.  The first chapter discusses the need for effectiveness and idea that effectiveness can be learned by anyone.  </p> <p>What is effectiveness you say?  Well, Drucker makes the distinction of doing the right things rather than do things the right way.  Too many are busy doing work with no clue as to what contribution that work is really making to the organization.</p> <p>After establishing the fact that effectiveness is important to knowledge workers and that effectiveness can be learned, the author then launches into 6 chapters explaining the most important aspects of practicing the habit of being effective.</p> <p>1.  Know where the time goes.</p> <p>2.  Focus on outward contribution.</p> <p>3.  Build on strengths - individual, peer, superior and subordinate.</p> <p>4.  Concentrate on a few major areas to achieve results.</p> <p>5.  Make effective decisions. </p> <p>I have not read all of the chapters, but just skimming the book has provided invaluable insights into becoming effective.  I will try to discuss each of the aspects above in future posts. </p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-61255847105396623212009-01-08T16:48:00.001-06:002009-01-08T16:48:37.254-06:00Random Resolution for the New Year 2009<p>Well, it's that time of year again when we make New Year's resolutions.  I am not a big fan of doing this once a year, because I believe that we should be daily looking for ways to grow and help others.</p> <p>However, I found out about a site that randomly chooses a resolution for you from Caleb Jenkin's <a href="http://calebjenkins.com/">blog</a> post <a href="http://developingux.com/2009/01/07/resolution-randomizer/">today</a>.  It sounded simple enough.  So, here's what it came up with for me.</p> <p><a href="http://resolutionrandomizer.pop.us/ecard.aspx"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="382" alt="resolution_randomizer_2009_toddmeinershagen" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipVJ18DQHonQIkzW5omSGYEe6kzjuACFzMAqhRGIkPZ5wbZs0HZodvCuBZk-JUa9CX3WMQGsKhcqsLO5EZyUOWJBLJ9wIvZi_9Ax_lIVkl7AilQyZCMQ5xJhqDxz0p0OuQPulVwUng0QY/" width="455" border="0" /></a></p> <p>Pretty appropriate, no?  Try it out by clicking <a href="http://resolutionrandomizer.pop.us/ecard.aspx">here</a>. </p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-41449388367471606302008-08-18T23:44:00.002-05:002008-08-18T23:46:25.286-05:00Type-Safe Enum Strings in .NET<p>One thing that has always bothered me in .NET is the inability to create a type-safe set of string constants like an enum. I would like to create a type such as the following: </p> <pre><span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">enum</span> StoredProcedure : <span style="color: rgb(0, 0, 255);">string</span><br />{<br /> DeleteConsumer = "<span style="color: rgb(139, 0, 0);">DeleteConsumer</span>",<br /> EditConsumer = "<span style="color: rgb(139, 0, 0);">EditConsumer</span>",<br /> GetConsumer = "<span style="color: rgb(139, 0, 0);">GetConsumer</span>"<br />}</pre><p>This would be incredibly useful for those situations where you are passing constant strings to a given method and you would like to limit the options that are passed to a finite set of options that can be detected through a type-safe check during compile time. </p><pre><span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">void</span> ExecuteDataSet(StoredProcedures storedProcedure)<br />{<br /> SqlCommand command = <span style="color: rgb(0, 0, 255);">new</span> SqlCommand();<br /> command.CommandType = CommandType.StoredProcedure;<br /> command.CommandText = storedProcedure.ToString();<br />}</pre><p>Unfortunately, a simple constant does not provide type-safe protection for the method call. If a developer is not aware of the pattern, they may end up sending in a literal string of their choosing. So, instead you end up with the following: </p><pre><span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">void</span> ExecuteDataSet(<span style="color: rgb(0, 0, 255);">string</span> storedProcedure)<br />{<br /> SqlCommand command = <span style="color: rgb(0, 0, 255);">new</span> SqlCommand();<br /> command.CommandType = CommandType.StoredProcedure;<br /> command.CommandText = storedProcedure.ToString();<br />}</pre><p>After working at a heterogeneous shop, I learned that Java has been creating their own type-safe string enum classes for solving this situation for years before the formal enum type was added to the 1.5 release of the Java Runtime. </p><p>The example below shows how a typical Java developer would implement this concept in Java syntax. </p><pre><span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">final</span> <span style="color: rgb(0, 0, 255);">class</span> Color {<br /><br /> <span style="color: rgb(0, 0, 255);">private</span> String name;<br /><br /> <span style="color: rgb(0, 0, 255);">private</span> Color(String name) {<br /> <span style="color: rgb(0, 0, 255);">this</span>.name = name;<br /> }<br /><br /> <span style="color: rgb(0, 0, 255);">public</span> String toString() {<br /> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 255);">this</span>.id;<br /> }<br /><br /> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> Color RED = <span style="color: rgb(0, 0, 255);">new</span> Color("<span style="color: rgb(139, 0, 0);">Red</span>");<br /> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> Color GREEN = <span style="color: rgb(0, 0, 255);">new</span> Color("<span style="color: rgb(139, 0, 0);">Green</span>");<br /> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">final</span> Color BLUE = <span style="color: rgb(0, 0, 255);">new</span> Color("<span style="color: rgb(139, 0, 0);">Blue</span>");<br />} </pre><p>The basic idea is simple:<br /></p><p>1. Define a class representing a single element of the enumerated type </p><p>2. Don't provide any public constructors for it. </p><p>3. Provide public static final fields, one for each constant in the enumerated type. </p><p>Because there is no way for clients to create objects of the type, there will never be any objects of the type besides those exported via the public static final fields. </p><p>In order to make this easier to use within .NET, I create an abstract base type, StringConstantBase, that allows a developer to quickly create the functionality above plus some other goodies such as GetNames(), CompareTo(), Equals(), GetHashCode(), and the == and != operators for comparison to string literals. </p><p>In order to use the code, you merely define your class as follows:</p><pre><span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> StoredProcedures : StringConstantBase<br />{<br /> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">readonly</span> StoredProcedures GetConsumer = <span style="color: rgb(0, 0, 255);">new</span> StoredProcedures("<span style="color: rgb(139, 0, 0);">GetConsumer</span>");<br /> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">readonly</span> StoredProcedures EditConsumer = <span style="color: rgb(0, 0, 255);">new</span> StoredProcedures("<span style="color: rgb(139, 0, 0);">EditConsumer</span>");<br /> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">readonly</span> StoredProcedures DeleteConsumer = <span style="color: rgb(0, 0, 255);">new</span> StoredProcedures("<span style="color: rgb(139, 0, 0);">DeleteConsumer</span>");<br /><br /> <span style="color: rgb(0, 0, 255);">private</span> StoredProcedures(<span style="color: rgb(0, 0, 255);">string</span> name) : <span style="color: rgb(0, 0, 255);">base</span>(name){}<br /><br />}</pre><p>The only part that does not work (this is the same for the Java version) is that it cannot be used in switch...case statements. Those require the use of an underlying integral type which is not present. Instead, you should use the if...else if construct to perform the same logic. </p><p>If you are interested in using the StringConstantBase class for your own code, you can download my Visual Studio 2008 project from here. In addition to the class, I have included a unit test project to include my assumptions on its use. </p><p>I hope this helps someone out there...</p>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-3027251526932156972008-07-17T07:23:00.001-05:002008-07-17T07:23:56.954-05:00Turning on Intellisense with Visual Studio 2008<p>For whatever reason, when I was using Visual Studio 2008 this morning, I noticed that intellisense was not working.  Whenever I typed the period at the end of an object reference, no list of available methods and their associated parameters was made visible as a drop-down.  </p> <p>I know that I am "man" enough to work without it, but I have come to really enjoy the productivity I get using intellisense - especially when learning a new API.</p> <p>So, after exploring a bit, I found the settings and am documenting it here, so I don't forget for future reference.</p> <p>1.  Click on Tools/Options in the upper-menu.</p> <p><a href="http://lh6.ggpht.com/todd.alan.meinershagen/SH850m-Y__I/AAAAAAAAAGs/HSCkCCsEpUc/image9.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="344" alt="image" src="http://lh3.ggpht.com/todd.alan.meinershagen/SH851Jmz9DI/AAAAAAAAAGw/AHdmmEV-X8c/image_thumb5.png" width="202" border="0" /></a> </p> <p>2.  Under Text Editor/All Languages navigate to the Statement Completion section at the top of the dialog and check the appropriate settings</p> <p><a href="http://lh5.ggpht.com/todd.alan.meinershagen/SH852YCsGyI/AAAAAAAAAG0/-645WJqA-F4/image8.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="296" alt="image" src="http://lh3.ggpht.com/todd.alan.meinershagen/SH853Ja7JyI/AAAAAAAAAG4/E7t_n-TcXMc/image_thumb4.png" width="471" border="0" /></a> </p> <p>There are 3 settings with the following explanation:</p> <ul> <li>Auto list members - this is essential for intellisense to begin working. </li> <li>Hide Advanced members - this will allow you to hide those properties, methods, and events that are not often used. </li> <li>Parameter information - by default the auto list members only displays the name of the property, event, or method.  You must have this option checked in order to display the actual parameter information. </li> </ul> <p>I hope this was helpful...</p> Unknownnoreply@blogger.comtag:blogger.com,1999:blog-2681574040796476559.post-67421296489701391492007-12-16T11:40:00.001-06:002007-12-16T11:40:59.836-06:00Alessio's In Westlake Village, CA<p>Tonight my manager and I are going to eat at Alessio's in Westlake Village, CA with a representative from IBM.  I just wanted to add this post as a reminder of the restaurant location.  I'm sure it will be very nice!</p> <p>I have placed a map of the directions from the Simi Valley office of Countrywide (2900 Madera Road) to the restaurant below for future reference.</p> <p></p> <p><iframe marginwidth="0" marginheight="0" src="http://maps.google.com/maps?f=d&hl=en&geocode=18039757214202201069,34.164031,-118.828507&time=&date=&ttype=&saddr=2900+Madera+Road,+Simi+Valley,+CA&daddr=3731+E+Thousand+Oaks+Blvd,+Westlake+Village,+CA+91362&mra=pi&mrcr=0&sll=34.164031,-118.828507&sspn=0.007493,0.016909&ie=UTF8&om=1&ll=34.225005,-118.82652&spn=0.13727,0.07712&output=embed&s=AARTsJpBm7yXVmLy4PduERGiFUhBuXKPuQ" frameborder="0" width="425" scrolling="no" height="350"></iframe> <br /><small><a style="color: #0000ff; text-align: left" href="http://maps.google.com/maps?f=d&hl=en&geocode=18039757214202201069,34.164031,-118.828507&time=&date=&ttype=&saddr=2900+Madera+Road,+Simi+Valley,+CA&daddr=3731+E+Thousand+Oaks+Blvd,+Westlake+Village,+CA+91362&mra=pi&mrcr=0&sll=34.164031,-118.828507&sspn=0.007493,0.016909&ie=UTF8&om=1&ll=34.225005,-118.82652&spn=0.13727,0.07712&source=embed">View Larger Map</a></small> </p> <p>Below is the actual location for the restaurant close up. </p> <p><iframe marginwidth="0" marginheight="0" src="http://maps.google.com/maps/ms?f=q&hl=en&geocode=&time=&date=&ttype=&ie=UTF8&cd=1&msa=0&msid=115608977194402490467.000440946915394130e38&ll=34.219751,-118.819199&spn=0.479604,1.082153&om=1&output=embed&s=AARTsJoCuusmbNtMPdSvaQqXi7RaaIEScw" frameborder="0" width="425" scrolling="no" height="350"></iframe> <br /><small><a style="color: #0000ff; text-align: left" href="http://maps.google.com/maps/ms?f=q&hl=en&geocode=&time=&date=&ttype=&ie=UTF8&cd=1&msa=0&msid=115608977194402490467.000440946915394130e38&ll=34.219751,-118.819199&spn=0.479604,1.082153&om=1&source=embed">View Larger Map</a></small></p> Unknownnoreply@blogger.com