tag:blogger.com,1999:blog-8048078637848099142024-03-18T14:16:53.092+01:00Legend and truthAn opinionated .Net developers blog. The official blog for FakeItEasy.Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.comBlogger71125tag:blogger.com,1999:blog-804807863784809914.post-51181955929937288892011-12-06T10:59:00.001+01:002011-12-06T10:59:07.867+01:00Undefined… uhhh… defined<p>Yes, we all know it, Javascript has some serious flaws. One of the more disturbing one being that undefined can be defined:</p><pre>// This is way legal, but way weird:
undefined = “defined”;</pre>
<p>Of course, it’s easy enough to avoid this, <strong>just don’t f-ing do it</strong>. But when writing scripts we are often playing in the same sandbox as the “big bad bullying, just straight up evil kids that has nothing better to do than going around defining undefined” are playing in. That’s why it’s very common to see scripts testing if the type of a value is “undefined” rather than to test if a value is equal to undefined:</p><pre>// Test...
if (typeof foo === “undefined”) doStuff();
// ... rather than ...
if (foo === undefined) doStuff();</pre>
<p>When I was a kid I alway wanted some sort of invisible shield to protected me from the big bad kids. Well, actually what I really, really wanted was some spinach to make me strong as Popey in order to beat the living crap out of the evil kids…</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic0fzTP_mtC_vhKG1yFDKd6rtzJb212F0T9GJdagTsPrChJFtA8_RJe_j5vc3nQ6wycg70pmiYPbIeAq_ZqRlWQ_Dysri7C15tTLeOGDbHj12WN1YSESYVvJU4gWCN-bDEbEkdcZlIR4U/s1600-h/popeye%25255B3%25255D.jpg"><img style="display: block; float: none; margin-left: auto; margin-right: auto" title="popeye" alt="popeye" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK6wZbnOMK_1QALMtCacCfWN0FC6nZMvLKDzsinmpbt_XOP44YMEDEUbWhvvWJEgRnViyI1hLU7h7pxsBb642LTeeQt1a_ULiQRIhI726i97D8WkYfiVEzZwJ1pOvNAKYBp1zCLv0-Sg0/?imgmax=800" width="182" height="240"></a></p>
<p>On the other hand, I guess a shield would do, I mean, even a visible shield would do. Can we please have a shield for our undefined??? Yes we can! And of course it comes in the form of a self invoking function as always when we want to shield our scripts.</p><pre>(function(undefined) {
if (something === undefined) doStuff();
}());
</pre>
<p>As you see here, we have an argument “undefined” in the function, however the function is self invoked without any argument thus the undefined argument has the value <em>undefined</em>. Inside this shield it’s perfectly safe to test for equality of undefined. This can be combined with other arguments as long as the undefined argument is the last one and the function is invoked with one argument less than the length of the arguments list:</p><pre>(function($, global, undefined) {
$(document).ready(function() {
if (something === undefined) doStuff();
});
}(jQuery, this));
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com74tag:blogger.com,1999:blog-804807863784809914.post-47509799999728831682011-04-10T10:51:00.001+02:002011-04-10T10:51:32.817+02:00An alternative to NotImplementedException<p>It happens from time to time that I forget to implement some code where I’m just throwing a NotImplementedException. Being forgetful I have a habit of coming up with stuff that will help me not to forget. I think my “MustBeImplementedException” is quite useful, it will break the build if the build is not DEBUG.</p><pre class="brush: csharp; gutter: false;">#if DEBUG
namespace FakeItEasy
{
using System;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// An exception that can be thrown before a member has been
/// implemented, will cause the build to fail when not built in
/// debug mode.
/// </summary>
[Serializable]
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "Never used in production.")]
public class MustBeImplementedException
: Exception
{
}
}
#endif
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-32053732726178640872011-04-02T13:37:00.001+02:002011-04-02T13:37:08.410+02:00An old pain point removed from FakeItEasy<p>It’s always bittersweet to say that you have introduced a breaking change in an API that people use. Bitter because it will break peoples code. But sweet because IT’S AN AWESOME NEW FEATURE!</p> <p>I was never really fond of the fact that argument constraints relies on implicit casting in FakeItEasy, this is why you had to write <strong>A<IFormattable>.Ignored.Argument</strong> but you could write the shorter <strong>A<string>.Ignored</strong> for non interface types. This had to be done in order for the chaining of argument constraints to work: <strong>A<string>.That.Contains(“foo”).And.Not.Contains(“bar”)</strong> for example. I thought I was pretty smart when I implemented this, it turns out though that ONCE in SEVERAL THOUSAND tests have I used this feature myself. Smart is never simple, smart is quite often stupid.</p> <p><em>Now, I don’t wanna be stupid</em>, so what can I do? <strong>I can remove the stupid feature</strong>. Said and done, in versions >= 1.7.* you can no longer chain argument constraints (but you weren’t doing that anyway).</p> <h2>Things that will break:</h2> <p>First of all, everything breaks at compile time so you won’t be able to build without fixing the problems. This is one of the benefits of a static type system, the complier will tell you what’s wrong!</p> <h3>.Argument</h3> <p>Any argument constraint will now return an instance of the constrained type (T) and not an ArgumentConstraint<T> as it did in previous versions. This means that there is not property .Argument so you will have to remove any calls to that property from your tests. This might be quite many calls depending on how many tests you have and what you have been testing.</p> <h3>ArgumentConstraint<T></h3> <p>As I said this class is no more (RIP). The lowest level api for creating constraints is now the “Matches(Func<T, bool> predicate, Action<IOutputWriter> descriptionWriter)” on the IArgumentConstraintManager<T> type. You access an argument constraint manager through the A<T>.That-property. This means that you can much more easily now provide extensions to the That-property, all you have to do is to create an extension method on IArgumentConstraintManager<T> and call the Matches-method inside your extension method. Here’s an example on how the IsNull() argument constraint is implemeneted.</p><pre class="brush: csharp; gutter: false;">/// <summary>
/// Constrains an argument so that it must be null (Nothing in VB).
/// </summary>
/// <typeparam name="T">The type of the argument.</typeparam>
/// <param name="manager">The constraint manager to match the constraint.</param>
/// <returns>A dummy argument value.</returns>
public static T IsNull<T>(this IArgumentConstraintManager<T> manager) where T : class
{
return manager.Matches(x => x == null, x => x.Write("NULL"));
}
</pre>
<p>If you have extended the That-property before all your extensions will have to be rewritten to use the new API, it’s quite a simple task though and you’ll be glad that it will be much easier to create new extensions.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com7tag:blogger.com,1999:blog-804807863784809914.post-21528987891180290942011-02-14T21:32:00.001+01:002011-02-14T21:32:49.079+01:00FakeItEasy breaking change for assertions<p>In the latest version of FakeItEasy (version 1.6.4062.205) there is a breaking change in how repeats are specified in assertions. The reason for this is that the old way – while logically correct – was not intuitive to a lot of people.</p> <p>Before you could write “Repeated.Once” and that assertion would pass even though the method you were asserting on had been called twice. Now, logically this makes perfect sense, a call that has happened twice has happened once. The problem is that I’ve noticed that people doesn’t think that way and therefore assertions has been wrong.</p> <p>The reason I hasn’t changed this before is that if I did change it it would be a breaking change and it would just change under the feet of people that had figured the behavior out and I was reluctant to make a breaking change that doesn’t break the build.</p> <p>The solution I came up with is one that does break the build. You can no longer write “Repeated.Once”, you have to write “Repeated.Exactly.Once” or “Repeated.AtLeast.Once” or “Repeated.NoMoreThan.Once” or any other repeat twice, Times(4) and so forth.</p> <p>Hopefully you agree with my decision that it was important to break the build in this case and I hope that it doesn’t cause too much frustration, it is actually a quite straight forward matter of find and replace.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com3tag:blogger.com,1999:blog-804807863784809914.post-42199436228166272292011-02-05T15:30:00.001+01:002011-02-05T15:30:46.734+01:00Experimental branches in Mercurial<p>Branching in Mercurial is easy, it’s so easy that most of the times you’re branching you don’t even know that you’re doing it. Have you ever had to merge? I guess you have, well guess what, when you’re merging, you’re merging two branches! Ever got an error when pushing stating that a push would create two heads in the remote repository? Head == branch.</p> <p>I had a conversation the other day with a fellow developer about Git, I asked him what the main benefits of Git was. The thing is I’m pretty much Git illiterate. One of the things he said was the ease of branching and how local “throw away” branches can’t be done in Mercurial. First of all, I don’t know exactly how easy this is in Git so it might be harder in Mercurial but it’s definitely not hard. Let me show you!</p> <p>I’ll use TortoiseHG in this example since it’s visual and makes for better examples but it is just as easy to do it from the command line.</p> <p>Let’s start with a repository that contains a code file:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikUtWeUoV-bRdF-cOwSMEjkOYP3mqPzGOLp9f4VWlFD2ltgJBy-gyEYOGZuUE5LP00UNlIpmXurs4UYs7bnrxzrJzWtjZDNQUAlP6aVqBLngju30yi72cc1ZEVzIBqfTS6wXkHM3L4JO4/s1600-h/image%5B5%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkMEuRh8bV8ogYk42lgZM0Q1TUgGwtgfuhlFk2_tV-L8YHJn96ccBED8e23hkvroZOHoCgvahIRhpMXc113uXjSpNpRxqAXjxY3OhZH2Oh2e1IKodOzX2qH3XnY7EFh0w80CVTVLBnatA/?imgmax=800" width="400" height="130"></a> </p> <p>Now, this class is boring, it only writes hello to the console and I’d like to spice it up a little, so I’ll do a spike. Let’s make it say “Hello Europe!”. Said and done, I edit the file and commit, now my repository looks like this:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDwg6xEkzoAFMdXPuzq1mN_9iLHwBL64312rMfOhFThK_Y0DzHUwkDOMAfcXP2XsoFmqOsBVDEAJ8Ke9G_N8C__Fwfqj1VU8Vf1KCrnfeQI2HkHnYyVpq3mhiCsynS3cElK1vbiWj_ygw/s1600-h/image%5B9%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_5E4uTsFQM2A-EMo7QkI_WpzbemunVpbVOeeUlEPykKrz3YWV52BwugGZpxjFLO7VfHilyitFP203kz82h4ygZr0Fzb_9UwmrHqE19GdALQQ2dEITM7Lc9PEKnnvZl_bZQbfc_c0pYkE/?imgmax=800" width="321" height="343"></a> </p> <p>Now the thing is, while “Hello Europe!” is good I’d like to explore something differnt, let’s make it say “Hello World!” that’s so much more international. Let’s go back to before the change:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXnbVO-XoPUKfnZ3aZLpSoDl3zcxQL_lL7Ik4j3UyY_lKa85UdQzMgEfpdG3r4tIg2QUyT_I-L1M9NIen2ARAd394bMN-uRnMhUl0lQpCba4LdmdsabXfWenbdSxRvdafTZsVeDKQ9RTU/s1600-h/image%5B24%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoCCcaiC2vvp373zCmhO1zmEi0Ckfps14uR8hgvlFt-b_4MPgZKsed4lOVJm5raT5f0R8l9nC_0en3z4YjbcUce2aTYBVZhTp14OuG2upL5JPmYh0JxkMFwFFZPQyxdoGLLFFM6usTvvo/?imgmax=800" width="299" height="320"></a> </p> <p>Now, I change the code again, this time to “Hello World!” then I commit, now the repo looks like this:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglIWNgXXa4p5U7SgGoWJI_MQw85fyP4Hac9BLAfEiit81LnJOn-qK2CkLb6afzhhPx_fMKvCFCmSx6ba_47uNp-kyKt2lRmMXDU5cDtJayWsIk5pUy2ewKd3eUL13w-i1jQeefP3evTjA/s1600-h/image%5B23%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX482aMQlAU14x4-JUNf9XgzElVkFSOxSNJqKydk0UMMFZkBN8oiiksCHdyir8qcW7MNEoqAwBf6es-nBrEWdtG0NZCrxRTNoMV_IIr4WpZ9FIlg0JtUpAP75WtFC05a3aedqGD-JkToU/?imgmax=800" width="293" height="332"></a> </p> <p>See, two branches, I could have backed to any point back in the revision history to branch from there. Now I’ve decided to go with the “Hello World!”-change and I want to push it to a central repo, I don’t want to include the “Hello Europe!” spike.</p> <p>Go into the repository explorer and click the “Determine and mark outgoing changesets”-button. This will mark change sets not already in the repository you’re pushing to with arrows:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSzpjsoLePLlH9bb0pFbYe6M8fDeEJZ1TlPLwFnUI2iNff3b4sqEWWaiRX9Qcyh51WrKSmigGGw7dphW4m7DgcwDhOgYnb13ZTaoNUL2RQDJZdIlUm7IOQGsgv-ynzdLb152UYlW48IHs/s1600-h/image%5B25%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbONysKgrGzJvD8AEnFnJyNpK2xWAeta2zM6vNyfrD9Ww7x6gM-MMdsOyj-WwII1Rx0IVy_MEsNSFwd7gflGH7PYF-Ro44LSenPcIX2CG0v-t7SALsjWyWSzxSODq3zrQkuq2aarS_Ouw/?imgmax=800" width="238" height="290"></a></p> <p>Right click the head of the branch you want to push and select “Push to here”. Now the repository you were pushing to will contain the following changesets:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvclXHNlEGHSiGCVUKvx9VRDFtTMLLV0VMEFhReHT0NyYcoywtFVEE824J3SM0IgTjWtJpRkWdXJpYT-N3N9cQYC2ZDoDEaRVTHpn9RWeo6d_tryx2cUN7tkRmOZN6O7oz92sKuUv8jB0/s1600-h/image%5B22%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk3xU9uOvPvqkIrcPp_TXoQNbr-BMb-A5mYwRHeXHZUq-SLUEY4joe8F3v2GlCrCMydO3Adzix9-D8-76vgGfsJumYk_rvrs5Nchm8wA4_xXicdX0JCovk81mRiHjQn7BIavPofAWYGk0/?imgmax=800" width="280" height="147"></a> </p> <p>That’s pretty much all there is to it! One more thing though, what about deleting local branches that you don’t want to keep? This can be done with the strip command in the <a title="MqExtensions" href="http://mercurial.selenic.com/wiki/MqExtension" target="_blank">MqExtensions</a> for Mercurial.</p> <p>Happy branching!</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-6226729530823444902010-10-04T22:31:00.001+02:002010-10-04T22:31:19.466+02:00Fixture initialization in FakeItEasy<p>I added a new feature to FakeItEasy that makes it – you guessed it – easy to initialize test fixtures with fakes.</p> <p>Instead of calling A.Fake<WhateverTypeYourFakingHere>() once for every fake you have in your test fixture you can simply tag the variables or properties you want to be fakes with the “FakeAttribute” and then call the method “Fake.InitializeFixture(this)” in your fixture setup:</p><pre class="brush: csharp; gutter: false;">[TestFixture]
public class InitializeFixtureIntegrationTests
{
[Fake] IFormatProvider formatProvider;
[Fake] IFormattable formattable;
[SetUp]
public void SetUp()
{
Fake.InitializeFixture(this);
}
[Test]
public void Should...
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-88414584006245151342010-09-26T21:03:00.001+02:002010-09-26T21:03:02.333+02:00Extending exception messages in FakeItEasy<p>One of the main features of <a title="FakeItEasy on Google code." href="http://code.google.com/p/fakeiteasy" target="_blank">FakeItEasy</a> is the informative exception messages, let’s say we have the following types:</p><pre class="brush: csharp; gutter: false;">public interface IPersonRepository
{
void Save(Person personToSave);
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
</pre>
<p>Now, let’s create a test that shows us what the exception messages in fake it easy looks like when asserting:</p><pre class="brush: csharp; gutter: false;">public void Extending_exception_messages()
{
var repository = A.Fake<IPersonRepository>();
repository.Save(new Person { FirstName = "Patrik", LastName = "Hägne", DateOfBirth = new DateTime(1977, 4, 5) });
A.CallTo(() => repository.Save(A<Person>.Ignored)).MustNotHaveHappened();
}
</pre>
<p>This will yield an exception message that looks like this:</p><pre> Assertion failed for the following call:
'FakeItEasy.Examples.IPersonRepository.Save(<ignored>)'
Expected to find it exactly never but found it #1 times among the calls:
1. 'FakeItEasy.Examples.IPersonRepository.Save(
personToSave: FakeItEasy.Examples.Person)'
</pre>
<p>While this is a good exception message it doesn't say a whole lot about the person object that was used in the call to save. You could ofcourse in this particular instance override the ToString-method of person to fix this, but a lot of times you don’t have control over the types you use (for example the framework types). Now, fortunately, in the latest release of FakeItEasy, there is a dead simple way for you to provide your own formatter for printed argument values.</p>
<p>All you have to do is in your testproject define a class that inherits the FakeItEasy.ArgumentValueFormatter<T>-class where T is the type of class you wish to provide custom formatting for.</p>
<p>Here’s an example of such a formatter for the Person-type:</p><pre class="brush: csharp; gutter: false;">public class PersonArgumentFormatter
: ArgumentValueFormatter<Person>
{
protected override string GetStringValue(Person argumentValue)
{
return string.Format("Person named {0} {1}, date of birth {2:yyyy-MM-dd} ({3} days old).",
argumentValue.FirstName,
argumentValue.LastName,
argumentValue.DateOfBirth,
DateTime.Now.Subtract(argumentValue.DateOfBirth).TotalDays);
}
}
</pre>
<p>Now, let’s run the same test again and see what the exception message looks like: (I’ve split the message over several lines in this post so that the message will not be truncated by the blog).</p><pre> Assertion failed for the following call:
'FakeItEasy.Examples.IPersonRepository.Save(<ignored>)'
Expected to find it exactly never but found it #1 times among the calls:
1. 'FakeItEasy.Examples.IPersonRepository.Save(
personToSave: Person named Patrik Hägne,
date of birth 1977-04-05 (12227,874689919 days old).)'
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-16375452082912374562010-07-24T11:18:00.001+02:002010-07-24T11:18:51.969+02:00FakeItEasy Login Service Example Series – Part 7<p>This is the seventh and last part in the series of posts where I’m porting <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">Brett Schucherts excelent demo of Mockito in Java</a> to C# and <a href="http://code.google.com/p/fakeiteasy/">FakeItEasy</a>. <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice">here</a>. <p>Part 1 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series.html">here</a>. <p>Part 2 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_16.html">here</a>. <p>Part 3 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_23.html">here</a>. <p>Part 4 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_25.html">here</a>. <p>Part 5 can be found <a href="http://ondevelopment.blogspot.com/2010/06/fakeiteasy-login-service-example-series.html">here</a>.</p> <p>Part 6 can be found <a href="http://ondevelopment.blogspot.com/2010/06/fakeiteasy-login-service-example-series_20.html">here</a>.</p> <h2>Test 7 – Should not be able to log in to revoked account</h2> <p>The next test is similar to the previous test. A revoked account does not allow logins:</p> <h3>The test</h3><pre class="brush: csharp; gutter: false;">[Test]
public void Should_throw_when_account_has_been_revoked()
{
// Arrange
A.CallTo(() => this.account.IsRevoked).Returns(true);
// Act, Assert
Assert.Throws<AccountRevokedException>(() =>
this.service.Login("username", "password"));
}
</pre>
<h3> </h3>
<h3>Test Description</h3>
<p>This test is a repeat of the previous test, checking for a different result from a different starting condition.</p>
<h3>Things Created for Compilation</h3>
<p>You'll need to add another exception, AccountRevokedException and a new property, IsRevoked, to IAccount.</p>
<h3>Code Updated to get Test to turn Green</h3>
<p>The only update to get to green is adding a check - a guard clause - similar to the previous test:</p><pre class="brush: csharp; gutter: false;">public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
if (account == null)
{
throw new AccountNotFoundException();
}
if (account.IsRevoked)
{
throw new AccountRevokedException();
}
if (account.IsLoggedIn)
{
throw new AccountLoginLimitReachedException();
}
if (account.PasswordMatches(password))
{
account.SetLoggedIn(true);
}
else
{
if (this.previousUsername.Equals(username))
{
this.numberOfFailedAttempts++;
}
else
{
this.numberOfFailedAttempts = 1;
this.previousUsername = username;
}
}
if (this.numberOfFailedAttempts == 3)
{
account.SetRevoked(true);
}
}
<font face="Verdana"></font></pre>
<h2>Summary</h2>
<p>This has been a port of Brett’s original tutorial, his tutorial does not end here though no more tests are added. Please continue reading <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">his tutorial</a>.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-14200534477876482332010-06-20T13:28:00.001+02:002010-06-20T13:28:19.774+02:00FakeItEasy Login Service Example Series – Part 6<p>This is the sixth part in the series of posts where I’m porting <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">Brett Schucherts excelent demo of Mockito in Java</a> to C# and <a href="http://code.google.com/p/fakeiteasy/">FakeItEasy</a>. <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice">here</a>. <p>Part 1 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series.html">here</a>. <p>Part 2 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_16.html">here</a>. <p>Part 3 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_23.html">here</a>. <p>Part 4 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_25.html">here</a>. <p>Part 5 can be found <a href="http://ondevelopment.blogspot.com/2010/06/fakeiteasy-login-service-example-series.html">here</a>. <h2>Test 6 – Exception thrown when account is not found</h2> <p>This is a final test to make sure the code handles the case of an account not getting found. This is not too hard to write:</p> <h3>The test</h3><pre class="brush: csharp; gutter: false;">[Test]
public void Should_throw_when_account_does_not_exist()
{
// Arrange
A.CallTo(() => this.accountRepository.Find(A<string>.Ignored)).ReturnsNull();
// Act, Assert
Assert.Throws<AccountNotFoundException>(() =>
this.service.Login("username", "password"));
}
</pre>
<h3>Test Description</h3>
<p>This test takes advantage of the fact that later configurations of a fake object takes precedence over earlier configurations, this differs from the way that Rhino Mocks works where earlier configurations has precedence.</p>
<p>A login is attempted which should fail.</p>
<h3>Things Created for Compilation</h3>
<p>To get this test to compile, you'll need to add a new exception class:<br><strong>AccountNotFoundException.</strong></p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class AccountNotFoundException
: Exception
{
}
}
</pre>
<h3>Code Updated to get Test to turn Green</h3>
<p>The test currently fails with a null reference exception, a quick fix is needed at the top of the method.<pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
private IAccountRepository accountRepository;
private int numberOfFailedAttempts;
private string previousUsername;
public LoginService(IAccountRepository accountRepository)
{
this.accountRepository = accountRepository;
this.previousUsername = string.Empty;
}
public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
if (account == null)
{
throw new AccountNotFoundException();
}
if (account.IsLoggedIn)
{
throw new AccountLoginLimitReachedException();
}
if (account.PasswordMatches(password))
{
account.SetLoggedIn(true);
}
else
{
if (this.previousUsername.Equals(username))
{
this.numberOfFailedAttempts++;
}
else
{
this.numberOfFailedAttempts = 1;
this.previousUsername = username;
}
}
if (this.numberOfFailedAttempts == 3)
{
account.SetRevoked(true);
}
}
}
}
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-46220889426339445302010-06-04T10:47:00.001+02:002010-06-04T10:47:49.948+02:00FakeItEasy Login Service Example Series – Part 5<p>This is the fifth part in the series of posts where I’m porting <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">Brett Schucherts excelent demo of Mockito in Java</a> to C# and <a href="http://code.google.com/p/fakeiteasy/">FakeItEasy</a>. <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice">here</a>. <p>Part 1 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series.html">here</a>. <p>Part 2 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_16.html">here</a>. <p>Part 3 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_23.html">here</a>. <p>Part 4 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_25.html">here</a>.</p> <h2>Test 5 – Do Not Allow a Second Login</h2> <p>In the actual problem, counting concurrent logins was somewhat complex. For this example, we'll keep it simple. If you are already logged in, you cannot log in a second time. That's simple enough:</p> <h3>The Test</h3><pre class="brush: csharp; gutter: false;">[Test]
public void Should_not_allow_concurrent_logins()
{
// Arrange
A.CallTo(() => this.account.PasswordMatches(A<string>.Ignored)).Returns(true);
A.CallTo(() => this.account.IsLoggedIn).Returns(true);
// Act, Assert</pre><pre class="brush: csharp; gutter: false;"> Assert.Throws<AccountLoginLimitReachedException>(() =>
this.service.Login("username", "password"));
}
</pre>
<h3>Test Description</h3>
<p>This test first sets the password to matching. However, it also sets a new property, IsLoggedIn, to always return true. It then attempts to login. The validation part of this test is in the Assert.Throws-part, which is a feature of NUnit.</p>
<h3>Things Created for Compilation</h3>First, create the new exception:<br><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class AccountLoginLimitReachedException : Exception { }
}
</pre>
<p>Next, add a new property to the IAccount interface, “IsLoggedIn”.<br>When you make these changes, the test will fail and the message indicates it expected an exception.
<h3>Code Updated to get Test to turn Green</h3>
<p>To get that exception thrown, simply make one small addition to the login method:</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
private IAccountRepository accountRepository;
private int numberOfFailedAttempts;
private string previousUsername;
public LoginService(IAccountRepository accountRepository)
{
this.accountRepository = accountRepository;
this.previousUsername = string.Empty;
}
public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
if (account.IsLoggedIn)
{
throw new AccountLoginLimitReachedException();
}
if (account.PasswordMatches(password))
{
account.SetLoggedIn(true);
}
else
{
if (this.previousUsername.Equals(username))
{
this.numberOfFailedAttempts++;
}
else
{
this.numberOfFailedAttempts = 1;
this.previousUsername = username;
}
}
if (this.numberOfFailedAttempts == 3)
{
account.SetRevoked(true);
}
}
}
}</pre><pre class="brush: csharp; gutter: false;"> </pre>
<p><em>Note that this code would’ve been refactored a number of times if it was not example code. -Patrik</em></p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-2037955884030114102010-05-25T20:42:00.001+02:002010-05-25T20:52:13.790+02:00FakeItEasy Login Service Example Series – Part 4<p>This is the fourth part in the series of posts where I’m porting <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">Brett Schucherts excelent demo of Mockito in Java</a> to C# and <a href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a>. <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice" target="_blank">here</a>. <p>Part 1 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series.html">here</a>. <p>Part 2 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_16.html">here</a>. <p>Part 3 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_23.html">here</a>. <h2>Test 4 – Two Fails on One Account Followed By Fail on Second Account</h2> <p>This is one of those requirements you ask "Really?!" This requirement comes from an actual project, so while it might sound bogus, it is an actual requirement from the real world.</p> <h3>The Test</h3><pre class="brush: csharp; gutter: false;">[Test]
public void Should_not_revoke_other_account_when_first_account_has_failed_to_log_in_twice()
{
// Arrange
A.CallTo(() => this.account.PasswordMatches(A<string>.Ignored)).Returns(false);
var secondAccount = A.Fake<IAccount>();
A.CallTo(() => secondAccount.PasswordMatches(A<string>.Ignored)).Returns(false);
A.CallTo(() => this.accountRepository.Find("other username")).Returns(secondAccount);
// Act
this.service.Login("username", "wrong password");
this.service.Login("username", "wrong password");
this.service.Login("other username", "wrong password");
// Assert
A.CallTo(() => secondAccount.SetRevoked(true)).MustNotHaveHappened();
}
</pre>
<h3>Test Description</h3>
<p>This test is a little longer because it requires more setup. Rather than possibly messing up existing tests and adding more setup to the fixture, I decided to do it in this test. There are alternatives to writing this test's setup:
<ul>
<li>Leave it as is, it's not too bad.
<li>Add the additional setup to the SetUp() method, making this a larger fixture.
<li>Put this test is another fixture, different setup --> different fixture (this would be more of a BDD style).</li></ul>
<p>Since my primary purpose of this tutorial is to demo FakeItEasy, I'll leave it as is until I notice additional duplication.<br></p>
<p>There are 4 parts to this test:</p>
<ol>
<li>Set the password matching to false on the account.
<li>Create a second account, with a never-matching password and register it with the account repository. Notice that this uses a particular account name, "other username". FakeItEasy, will use the latest configured call before any earlier configurations so this rule has precedence over the configuration in the setup that matches any account name.
<li>Login two times to the first account (both failing), then log in to a second account, also failing. That's three failures in a row, but to two different accounts, so no account should be revoked.
<li>Verify that the secondAccount is not revoked.</li></ol>
<h3>Things Created for Compilation</h3>
<p>This test compiles without any new methods. It does fail with the following exception:</p><pre>Assertion failed for the following call:
'FakeItEasy.Examples.LoginService.IAccount.SetRevoked(True)'
Expected to find it exactly never but found it #1 times among the calls:
1. 'FakeItEasy.Examples.LoginService.IAccount.PasswordMatches("wrong password")'
2. 'FakeItEasy.Examples.LoginService.IAccount.SetRevoked(True)'</pre>
<h3>Code Updated to get Test to turn Green</h3>
<p>To get this new test to pass, I added a new member to the LoginService class: previousUsername. Then I updated the login method to take advantage of it:</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
private IAccountRepository accountRepository;
private int numberOfFailedAttempts;
private string previousUsername;
public LoginService(IAccountRepository accountRepository)
{
this.accountRepository = accountRepository;
this.previousUsername = string.Empty;
}
public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
if (account.PasswordMatches(password))
{
account.SetLoggedIn(true);
}
else
{
if (this.previousUsername.Equals(username))
{
this.numberOfFailedAttempts++;
}
else
{
this.numberOfFailedAttempts = 1;
this.previousUsername = username;
}
}
if (this.numberOfFailedAttempts == 3)
{
account.SetRevoked(true);
}
}
}
}</pre>
<p>This allows all tests to pass. Would it have been possible to do less? Maybe, but this was the first thing that came to mind. The code is starting to be a bit unruly. We're just about ready to clean up this code, but before we do there are a few more tests.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com4tag:blogger.com,1999:blog-804807863784809914.post-15532825277098996142010-05-23T18:21:00.001+02:002010-05-25T20:52:36.944+02:00FakeItEasy Login Service Example Series – Part 3<p>This is the fourth part in the series of posts where I’m porting <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">Brett Schucherts excelent demo of Mockito in Java</a> to C# and <a href="http://code.google.com/p/fakeiteasy/">FakeItEasy</a>. <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice">here</a>. <p>Part 1 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series.html">here</a>. <p>Part 2 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series_16.html">here</a>. <h2>Test 3 – Not logging in with wrong password</h2> <p>The first two tests have made good progress, however to keep the number of assertions per test small (so far one) and to make individual tests less dependent on the underlying implementation, this next test forces a fix to the code and probably would have been a better second test than one you just created.</p> <h3>The Test</h3><pre class="brush: csharp; gutter: false;">[Test]
public void Should_not_log_in_when_password_is_wrong()
{
// Arrange
A.CallTo(() => this.account.PasswordMatches(A<string>.Ignored)).Returns(false);
// Act
this.service.Login("username", "wrong password");
// Assert
A.CallTo(() => this.account.SetLoggedIn(true)).MustNotHaveHappened();
}
</pre>
<h3>Test Description</h3>
<p>This test takes advantage of the recent test refactoring. Before ever getting into the test method, the SetUp method:
<ol>
<li>Created a fake IAccount.
<li>Created a fake IAccountRepository.
<li>Configured the IAccountRepository fake to return the fake IAccount for any username.
<li>Created a LoginService and injected the IAccountRepository.</li></ol>
<p>There’s not much left:</p>
<ol>
<li>Set the fake IAccount to not match any password.
<li>Attempt to login.
<li>Assert that the SetLoggedIn method is never called with true.</li></ol>
<h3>Things Created for Compilation</h3>
<p>This test did not require any existing classes to have new methods added.</p>
<h3>Failing Test</h3>
<p>The test fails with this message, FakeItEasy finds the specified method call once and lists all the calls to the faked IAccount.</p><pre> Assertion failed for the following call:
'FakeItEasy.Examples.LoginService.IAccount.SetLoggedIn(True)'
Expected to find it exactly never but found it #1 times among the calls:
1. 'FakeItEasy.Examples.LoginService.IAccount.SetLoggedIn(True)'
2. 'FakeItEasy.Examples.LoginService.IAccount.PasswordMatches("wrong password")'</pre><pre> </pre>
<h3>Code Updated to get Test to turn Green</h3>
<p>The LoginService needs to be updated:</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
private IAccountRepository accountRepository;
private int numberOfFailedAttempts;
public LoginService(IAccountRepository accountRepository)
{
this.accountRepository = accountRepository;
}
public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
if (account.PasswordMatches(password))
{
account.SetLoggedIn(true);
}
else
{
this.numberOfFailedAttempts++;
}
if (this.numberOfFailedAttempts == 3)
{
account.SetRevoked(true);
}
}
}
}</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-32161429394851025212010-05-16T13:43:00.001+02:002010-05-25T20:52:47.758+02:00FakeItEasy Login Service Example Series – Part 2<p>This is the fourth part in the series of posts where I’m porting <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample">Brett Schucherts excelent demo of Mockito in Java</a> to C# and <a href="http://code.google.com/p/fakeiteasy/">FakeItEasy</a>. <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice">here</a>. <p>Part 1 can be found <a href="http://ondevelopment.blogspot.com/2010/05/fakeiteasy-login-service-example-series.html">here</a>.</p> <h2>Test 2 – Revoking accounts</h2> <h3>User story</h3> <blockquote> <p>After three consecutive failed login attempts to the account, the account shall be revoked.</p></blockquote> <h3>The test</h3><pre class="brush: csharp; gutter: false;">[Test]
public void Should_revoke_account_after_three_failed_login_attempts()
{
// Arrange
var account = A.Fake<IAccount>();
A.CallTo(() => account.PasswordMatches(A<string>.Ignored)).Returns(false);
var accountRepository = A.Fake<IAccountRepository>();
A.CallTo(() => accountRepository.Find(A<string>.Ignored)).Returns(account);
var service = new LoginService(accountRepository);
// Act
service.Login("username", "wrong password");
service.Login("username", "wrong password");
service.Login("username", "wrong password");
// Assert
A.CallTo(() => account.SetRevoked(true)).MustHaveHappened(Repeated.Once.Exactly);
}
</pre>
<h3>Test description</h3>
<ol>
<li>Create a faked IAccount. Unlike the first test, this fake never matches any password.
<li>Create an IAccountRepository fake and register the IAccount fake with it for any username.
<li>Create the LoginService as before, injecting the IAccountRepository fake.
<li>Attempt to login three times, each time should fail.
<li>Finally, verify that the account was set to revoked after three times. <em>Note that I specify the number of times it should be repeated to once exactly in this case, this is to show the syntax for how to specify repeat. In the first test we just said that the call should have happened any number of times, in this test we say that it must have happened exactly once. -Patrik</em></li></ol>
<p>Notice that this test does not check that SetLoggedIn is not called. It certainly could and that would make it in a sense more complete. On the other hand, it would also tie the test verification to the underlying implementation and also be testing something that might better be created as its own test (so that’s officially on the punch-list for later implementation).</p>
<h3>Things created for compilation</h3>
<p>Added the new method SetRevoked(bool isRevoked) to the IAccount-interface.</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
public interface IAccount
{
bool PasswordMatches(string password);
void SetLoggedIn(bool isLoggedIn);
void SetRevoked(bool isRevoked);
}
}
</pre>
<h3>Failing test</h3>
<p>The test fails with the following message:</p><pre>Assertion failed for the following call:<br> 'FakeItEasy.Examples.LoginService.IAccount.SetRevoked(True)'<br>Expected to find it exactly once but found it #0 times among the calls:<br> 1. 'FakeItEasy.Examples.LoginService.IAccount.SetLoggedIn(True)' repeated 3 times</pre><pre> </pre>
<p><em>Note that all the calls that has been made to the fake object are listed in the message so that you can easily see what is happening and why the test is failing. -Patrik</em></p>
<h3>Code updated to get test to turn green</h3>
<p>Here’s one way to make this test pass (and keep the first test green).</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
private IAccountRepository accountRepository;
private int numberOfFailedAttempts;
public LoginService(IAccountRepository accountRepository)
{
this.accountRepository = accountRepository;
}
public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
account.SetLoggedIn(true);
if (!account.PasswordMatches(password))
{
this.numberOfFailedAttempts++;
}
if (this.numberOfFailedAttempts == 3)
{
account.SetRevoked(true);
}
}
}
}
</pre>
<h3>Refactoring</h3>
<p>Sure it is a bit ugly and we can certainly improve on the structure. Before doing that, however, we'll let the production code ripen a bit to get a better sense of its direction. Instead, let's spend some time removing duplication in the unit test code. Rather than make you work through several refactoring steps, here's the final version I came up with:</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.LoginService.Tests
{
using FakeItEasy.Examples.LoginService;
using NUnit.Framework;
[TestFixture]
public class LoginServiceTests
{
private IAccount account;
private IAccountRepository accountRepository;
private LoginService service;
[SetUp]
public void SetUp()
{
this.account = A.Fake<IAccount>();
this.accountRepository = A.Fake<IAccountRepository>();
A.CallTo(() => this.accountRepository.Find(A<string>.Ignored)).Returns(this.account);
this.service = new LoginService(this.accountRepository);
}
[Test]
public void Should_set_account_to_logged_in_when_password_matches()
{
// Arrange
A.CallTo(() => this.account.PasswordMatches(A<string>.Ignored)).Returns(true);
// Act
this.service.Login("username", "password");
// Assert
A.CallTo(() => this.account.SetLoggedIn(true)).MustHaveHappened();
}
[Test]
public void Should_revoke_account_after_three_failed_login_attempts()
{
// Arrange
A.CallTo(() => this.account.PasswordMatches(A<string>.Ignored)).Returns(false);
// Act
this.service.Login("username", "wrong password");
this.service.Login("username", "wrong password");
this.service.Login("username", "wrong password");
// Assert
A.CallTo(() => this.account.SetRevoked(true)).MustHaveHappened(Repeated.Once.Exactly);
}
}
}
</pre>
<p>This simply extracts common setup to an init() method. However, this cleanup really shortens the individual tests considerably. It also makes their intent clearer.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-48262433019313903032010-05-15T12:59:00.001+02:002010-05-25T20:53:10.828+02:00FakeItEasy Login Service Example Series – Part 1<p>This is the first part in a series of blog posts that will demo <a title="FakeItEasy on Google code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a> through TDD-ing a simple Login Service using C#.</p> <p>This is a port of <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample" target="_blank">Brett Schucherts excelent demo of Mockito in Java</a>. As this is a demo of FakeItEasy, I will omit the refactoring part of Brett’s original example, please don’t miss it though as it can be found <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample#refactorproduction" target="_blank">here</a>. I’ve tried to stay as close to the original example as possible so that they can be easily compared.</p> <p>The source for this example series can be found in a Mercurial repository at Google code. Each test implementation and following code update is a separate commit so you can easily update your repository to look at the full code at any given state. Find the repository <a href="http://code.google.com/p/fakeiteasy/source/checkout?repo=schucherloginservice">here</a>. <h2>Getting started</h2> <ul> <li>Create a new class library project in Visual Studio (or your IDE of choice). <li>Create a new class library for the tests. <li>Add a reference to the class library project from the test project. <li>Download <a title="FakeItEasy on Google code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a> and add a reference to FakeItEasy.dll from your test project. (Version 1.0.0.2 is used when writing this example.) <li>Download <a title="NUnit home." href="http://www.nunit.org/" target="_blank">NUnit</a> and add a reference to nunit.framework.dll from your test project. (Version 2.5.0.9122 is used when writing this example.)</li></ul> <h2>Writing the tests</h2> <p>What follows is a series of tests to get enough production code written to suggest a better implementation. The first purpose of this tutorial is to demonstrate using FakeItEasy for all types other than the underling LoginService. This is close to a <a href="http://martinfowler.com/articles/mocksArentStubs.html#SoShouldIBeAClassicistOrAMockist">classic mockist approach</a>, though it varies in that I'm emphasizing testing interaction rather than state and deliberately trying to write stable tests that do not depend too much on the underling implementation. In support of this: <ul> <li>All types used or needed by the underling LoginService will be represented as Interfaces (Interfaces will start with an I). <li>All types used or needed by the underling LoginService will be created via FakeItEasy. <li>I'm going to use Loose mocks - that is, you can call anything you want and the underling object will not complain. This is the default behavior of FakeItEasy. <li>I'm going to minimally verify the expected resulting interactions (one assertion per test). <li>I’ll only refactor the unit tests, for more on the refactoring of the production code see Brett’s original: <a href="http://schuchert.wikispaces.com/Mockito.LoginServiceExample#refactorproduction">refactoring to the state pattern</a>.</li></ul> <h2>Test 1 – Basic Happy Path</h2> <h3>User Story</h3> <h3></h3> <blockquote> <p>When a user logs in successfully with a valid account id and password, the account’s state is set to logged in.</p> <h3></h3></blockquote> <h3>The test</h3><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.LoginService.Tests
{
using FakeItEasy.Examples.LoginService;
using NUnit.Framework;
[TestFixture]
public class LoginServiceTests
{
[Test]
public void Should_set_account_to_logged_in_when_password_matches()
{
// Arrange
var account = A.Fake<IAccount>();
A.CallTo(() => account.PasswordMatches(A<string>.Ignored)).Returns(true);
var accountRepository = A.Fake<IAccountRepository>();
A.CallTo(() => accountRepository.Find(A<string>.Ignored)).Returns(account);
var service = new LoginService(accountRepository);
// Act
service.Login("username", "password");
// Assert
A.CallTo(() => account.SetLoggedIn(true)).MustHaveHappened();
}
}
}
</pre>
<h3>Test description</h3>
<ol>
<li>This test first creates a fake for an IAccount. There's no actual account class, just the interface. This fake is configured so that no matter what password is sent to it, it will always return true when asked if a provided password matches its password.
<li>Create a fake of an IAccountRepository. Associate the fake IAccount with the fake IAccountRepository. When asking for any account with any username return the account fake created at the start of this method.
<li>Create a LoginService, injecting the IAcccountRepsitory in the constructor. This is an example of Inversion of Control, rather than the LoginService knowing which IAccountRepository to talk to, it is told which one to talk to. So while the LoginService knows which messages to send to an IAccountService, it is not responsible for deciding to<em> <strong>which</strong></em> instance it should send messages.
<li>Actually send a login message, looking for account with username "username" and a password of "password". Notice that if things are configured correctly, any username will match as will any password.
<li>Use FakeItEasy to assert that the SetLoggedIn-method of the account was called.</li></ol>
<h3>Things Created for Compilation</h3>
<p>To get this test to compile (but not yet pass), I had to create a few interfaces and add some methods to them. I also had to create a LoginService class:</p>
<h4>IAccount</h4><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
public interface IAccount
{
bool PasswordMatches(string password);
void SetLoggedIn(bool isLoggedIn);
}
}
</pre>
<h4>IAccountRepository</h4><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
public interface IAccountRepository
{
IAccount Find(string username);
}
}
</pre>
<h4>LoginService</h4><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
public void Login(string username, string password)
{
}
}
}
</pre>
<h3>Failing test</h3>
<p>Creating the test and adding all of theses classes gets my first test to Red with the following error:</p><pre>Assertion failed for the following call:
'FakeItEasy.Examples.LoginService.IAccount.SetLoggedIn(True)'
Expected to find it once but no calls were made to the fake object.</pre>
<h3></h3>
<h3>Passing the test</h3>
<p>The test as written requires that the production code (LoginService) sends a message to a particular IAccount object. The LoginService retrieves accounts via its IAccountRepository, which it received during construction. So all we need to do is remember that particular IAccountRepository object and use it:</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Examples.LoginService
{
using System;
public class LoginService
{
private IAccountRepository accountRepository;
public LoginService(IAccountRepository accountRepository)
{
this.accountRepository = accountRepository;
}
public void Login(string username, string password)
{
var account = this.accountRepository.Find(username);
account.SetLoggedIn(true);
}
}
}
</pre>
<h2>Conclusion</h2>
<p>There we have it, our first test case implemented, in the next part we’ll create another test.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com6tag:blogger.com,1999:blog-804807863784809914.post-76476172313647576092010-05-05T21:28:00.001+02:002010-05-09T23:07:04.650+02:00You don’t understand everything until you understand Nothing<p>Here’s a piece of code that might or might not do what you expect. (It depends on what you expect it to do.)</p><pre>Dim someAge = "999"
Dim parsedAge As Integer? = If(someAge = "999", Nothing, Integer.Parse(someAge))
</pre>
<h3>Challenge</h3>
<p>What will the parsedAge variable contain?</p>
<h3>Answer</h3>
<p>It will be a nullable integer with no value, right? <strong>Ehh, no wrong!</strong> </p>
<p>-So, what will it be?</p>
<p>Well, it will be a nullable integer – that’s the easy part – but it will have a value, zero (0)! Is this what you expected? It’s not what I expected when just gleening over the code. It’s not wrong or anything, it’s just that it’s not particularly intuitive.</p>
<p>It might be easier to see what happens here if we try to rewrite the same code in C#:</p><pre class="brush: csharp;">string someAge = “999”;
int? parsedAge = someAge == “999” ? null : int.Parse(someAge);
</pre>
<p>This will not even compile because the ternary operator must evaluate to a type and the compiler can’t figure out which type you want since an int value and <strong>null</strong> can never be of the same type.</p>
<p>So, why does it compile in VB? Well, because…</p>
<blockquote>
<p>… <em><strong>Nothing</strong> is not the same as <strong>null</strong>…</em></p></blockquote>
<p>- Huh? Nothing in VB is the same as null in C# right?</p>
<p>- Ehh, wrong!</p>
<p><strong>Nothing</strong> is much more like the “<strong>default</strong>” keyword in C#. <strong>Nothing</strong> can be assigned to value type variables which will contain the default value of that type:</p>
<p>So let’s write C# code that is in fact equivalent to the VB code:</p><pre class="brush: csharp;">string someAge = “999”;
int? parsedAge = someAge == “999” ? default(int) : int.Parse(someAge);
</pre>
<p>Now, ofcourse “default(int)” will always return “0” so we could just as well write this:</p><pre class="brush: csharp;">int? parsedAge = someAge == “999” ? 0 : int.Parse(someAge);
</pre>
<p>Now it might be a bit more clear what happens; the ternary operator will <em>always</em> return an integer, either zero or the parsed string value, it will <em>never</em> return <strong>null</strong> and it will <em>never</em> return a nullable integer.</p>
<p>Now this is probably what threw me off to begin with: the result of the ternary operator is assigned nullable integer, leading us to believe that the result of the operator is a nullable integer when it infact never is. An int will be implicitly converted to a nullable int so the compiler will not complain here even though we technically have a type mismatch.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-25824477981427349872010-02-25T19:36:00.001+01:002010-02-25T19:36:04.847+01:00Return from sequence in FakeItEasy<p>I added a nifty little feature in FakeItEasy today, not 100% sure about the naming though so if you have any ideas pleas tell me. The idea is that when you configure a call you can specify several values and each time a call is made to the configured member (property or method) the next value from the collection will be returned. Here’s what it looks like in action:</p><pre class="brush: csharp; gutter: false;">public interface ICurrentTimeProvider
{
DateTime CurrentTime { get; }
}
[Test]
public void Example()
{
var timeProvider = A.Fake<ICurrentTimeProvider>();
A.CallTo(() => timeProvider.CurrentTime).ReturnsNextFromSequence(
DateTime.Parse("2000-01-01 01:00"),
DateTime.Parse("2000-01-01 01:01"),
DateTime.Parse("2000-01-01 01:02"));
Console.WriteLine(timeProvider.CurrentTime); // Writes 2000-01-01 01:00
Console.WriteLine(timeProvider.CurrentTime); // Writes 2000-01-01 01:01
Console.WriteLine(timeProvider.CurrentTime); // Writes 2000-01-01 01:02
}
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-56326547336387377542010-01-06T11:13:00.001+01:002010-01-06T11:13:27.145+01:00Not implemented? Implemented.<p>I use the <a title="NotImplementedException on MSDN." href="http://msdn.microsoft.com/en-us/library/system.notimplementedexception.aspx" target="_blank">System.NotImplementedException</a> a lot, whenever I create a new method I have it throwing this until I have let tests drive actual functionality of the method. There is a slight danger in this though (although better than the alternative) in that I might forget to implement a function and this exception creeps into production.</p> <p>The other day I modified the snippet I use so that it outputs pre processor directives, so that the compiler will refuse to compile the code if I forget to implement such a method.</p><pre class="brush: csharp; gutter: false;">#if DEBUG
throw new NotImplementedException();
#else
#error "Must be implemented to compile in configurations where the DEBUG constant is not defined."
#endif
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com2tag:blogger.com,1999:blog-804807863784809914.post-62370053298976285052009-12-27T21:14:00.001+01:002009-12-27T21:14:05.642+01:00Argument validation in FakeItEasy<p>I created two more screencasts on <a href="http://code.google.com/p/fakeiteasy" target="_blank">FakeItEasy</a>, these two are on the subject on argument validation, I’ve increased the font size and put some compressor on the audio to improve the quality a bit.</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:11ec0791-fe98-4894-96aa-befa0246f29d" class="wlWriterEditableSmartContent"><div id="9bbee6e9-5d6b-436f-9b36-1eddffb98b09" style="margin: 0px; padding: 0px; display: inline;"><div><a href="http://www.youtube.com/watch?v=w71eNpN_uzk" target="_new"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHxSaO-BpLsQE0OzRtYIF0gkG9_8eHGnivDENFuREV91v7SGB5Yo1_zQsoFkRgqAMBNeL0N6Nq-EMqVFkR2xtckiZm8mLULxQ6tGhoFU6DaVSQgcyWh30QHiB2VAt-lHPvwkAzu79u2vE/?imgmax=800" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('9bbee6e9-5d6b-436f-9b36-1eddffb98b09'); downlevelDiv.innerHTML = "<div><object width=\"425\" height=\"355\"><param name=\"movie\" value=\"http://www.youtube.com/v/w71eNpN_uzk&hl=en\"><\/param><embed src=\"http://www.youtube.com/v/w71eNpN_uzk&hl=en\" type=\"application/x-shockwave-flash\" width=\"425\" height=\"355\"><\/embed><\/object><\/div>";" alt=""></a></div></div></div> <p> </p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:fdc0c520-6370-45d7-8bcc-2fa8d0b10186" class="wlWriterEditableSmartContent"><div id="82f2eae8-dc3a-47e1-92c5-bf0756f73ef3" style="margin: 0px; padding: 0px; display: inline;"><div><a href="http://www.youtube.com/watch?v=j2d5Cro_NlM" target="_new"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNhTCSt5DesRlB6otzjvjWBS5Bg8zvHQb-bdB17d-BT_jXekmoxQ42omjiFLHJw75ykDPVnbM_8HDjAnkkoxjO5amrKfmf5Y3pi5iaI-P4Ex9GShIGcmYzX5jiolN6BRXDnE6H4SGgru4/?imgmax=800" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('82f2eae8-dc3a-47e1-92c5-bf0756f73ef3'); downlevelDiv.innerHTML = "<div><object width=\"425\" height=\"355\"><param name=\"movie\" value=\"http://www.youtube.com/v/j2d5Cro_NlM&hl=en\"><\/param><embed src=\"http://www.youtube.com/v/j2d5Cro_NlM&hl=en\" type=\"application/x-shockwave-flash\" width=\"425\" height=\"355\"><\/embed><\/object><\/div>";" alt=""></a></div></div></div> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-86623479496652173532009-12-26T17:47:00.001+01:002009-12-26T17:48:45.653+01:00The basics of FakeItEasy<p>I thought I’d take a stab at screencasts so here’s my first attempt, it’s a quick overview of the FakeItEasy framework:</p> <p>(I would highly recommend that you watch it in HD-quality, otherwise the text will not be readable.)</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:a327e207-81a7-44b8-a750-980a027805ef" class="wlWriterEditableSmartContent"><div id="2e616ba7-00e2-4ef6-a37f-928cc18ef0f1" style="margin: 0px; padding: 0px; display: inline;"><div><a href="http://www.youtube.com/watch?v=4Oacd2UNADo" target="_new"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinC2TF190b5NwEMsFevB7Za2IGxQEKFqNhrPMyhyD9R2RUJYhkdoyY8Z8NE575JzRueimKRGZ9a5SZxsZMhhosg7ObKQa1s0j-xJowg7EEPLxnxQ3n_TC8JDbPUy34uIvtjfXU8hsP8rQ/?imgmax=800" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('2e616ba7-00e2-4ef6-a37f-928cc18ef0f1'); downlevelDiv.innerHTML = "<div><object width=\"425\" height=\"355\"><param name=\"movie\" value=\"http://www.youtube.com/v/4Oacd2UNADo&hl=en\"><\/param><embed src=\"http://www.youtube.com/v/4Oacd2UNADo&hl=en\" type=\"application/x-shockwave-flash\" width=\"425\" height=\"355\"><\/embed><\/object><\/div>";" alt=""></a></div></div></div> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com3tag:blogger.com,1999:blog-804807863784809914.post-35035103576409564382009-12-19T12:40:00.001+01:002009-12-19T12:40:12.469+01:00Configuring any call to an object<p>I’ve just updated the way to configure any call to faked objects in <a title="FakeItEasy on Google Code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a>, the syntax is new and also you can now configure return values.</p> <p>Let’s say you have an interface providing localized text resources like this:</p><pre class="brush: csharp; gutter: false;">public interface ILocalizedResources
{
string SomeText { get; }
string SomeOtherText { get; }
}
</pre>
<p>When you fake this interface any of the properties would return null when not configured but you might have several tests that are dependant on that the values are non null strings but still you don’t want to have to configure each individual property in the set up of you fixture. Now you can do exactly that:</p><pre class="brush: csharp; gutter: false;">var resources = A.Fake<ILocalizedResources>();
Any.CallTo(resources).WithReturnType<string>().Returns("");
</pre>
<p>Of course you can still configure any call to do anything you want just as before, for example:</p><pre class="brush: csharp; gutter: false;">var resources = A.Fake<ILocalizedResources>();
Any.CallTo(resources).Throws(new Exception());
</pre>
<p> </p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:58dbac91-aaf1-43c7-b012-416b1cbee94e" class="wlWriterEditableSmartContent">Technorati-taggar: <a href="http://technorati.com/tags/Mock" rel="tag">Mock</a>,<a href="http://technorati.com/tags/Stub" rel="tag">Stub</a>,<a href="http://technorati.com/tags/Fake" rel="tag">Fake</a>,<a href="http://technorati.com/tags/TDD" rel="tag">TDD</a>,<a href="http://technorati.com/tags/FakeItEasy" rel="tag">FakeItEasy</a>,<a href="http://technorati.com/tags/.Net" rel="tag">.Net</a>,<a href="http://technorati.com/tags/c%23" rel="tag">c#</a></div> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-44869930454794173552009-12-10T11:20:00.001+01:002009-12-10T11:20:10.052+01:00T4<p>No, not that crappy movie but <a title="About T4 on MSDN." href="http://msdn.microsoft.com/en-us/library/bb126445.aspx" target="_blank">Text Template Transformation Toolkit</a>.</p> <p>I’ve played around with T4 every now and then over the last year but I’ve struggled to find any <em>really</em> good source for learning more. I guess the man who stands out from the crowd is <a title="Oleg's blog." href="http://www.olegsych.com/" target="_blank">Oleg Sych</a> who has blogged about it en masse.</p> <p>I’m watching a new <a title="Screen cast about T4 on Channel 9." href="http://channel9.msdn.com/posts/VSIPMarketing/VSX206-Code-Generation-with-T4/" target="_blank">screen cast</a> by him on Channel 9 right now and it’s really good so please check it out.</p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-18240759244474930162009-11-26T21:06:00.001+01:002009-11-26T21:06:57.868+01:00New configuration syntax for FakeItEasy<p>I’ve implemented a new, cleaner simpler, ninja-deluxe-shiny-gold-plated-ultra-cool way of configuring fakes/stubs/mocks in <a title="FakeItEasy at Google Code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a>.</p> <p>The news are two fold:</p> <ol> <li>Simpler call specifications <li>Simpler argument validations</li></ol> <p>How’s this for simple?</p><pre class="brush: csharp; gutter: false;">public void Example()
{
var serviceProvider = A.Fake<IServiceProvider>();
var service = A.Fake<IWidgetFactory>();
A.CallTo(() => serviceProvider.GetService(typeof(IWidgetFactory))).Returns(service);
}
</pre>
<p>No need for awkward lambda expressions where you have to split the configured method from the object that it’s called on.</p>
<p>Instead of:</p><pre class="brush: csharp; gutter: false;">serviceProvider.CallsTo(x => x.GetService(typeof(IWidgetFactory))
</pre>
<p>This reads better:</p><pre class="brush: csharp; gutter: false;">A.CallTo(() => serviceProvider.GetService(typeof(IWidgetFactory)))
</pre>
<p>As I mentioned argument validation has also become simpler, I mean, this is just childs play isn’t it?</p><pre class="brush: csharp; gutter: false;">A.CallTo(() => serviceProvider.GetService(A<Type>.Ignored)).Throws(new Exception());
A.CallTo(() => serviceProvider.GetService(A<Type>.That.Matches(_ => _.Name.StartsWith("A")))).Throws(new Exception());
</pre>
<p>The really cool thing is that you can define your own extension methods that provides validations for arguments, these extension will show up on the “That”-property, like this:</p><pre class="brush: csharp; gutter: false;">A<Type>.That.IsValidatedByMyVeryOwnExtensionMethod();
A<Type>.That.IsInSystemNamespace();
A<string>.That.SpellsMyName();
</pre>
<p>It can be whatever you want, this means that you can effectively provide your own DSL for argument validation.</p>
<p>I’m thinking about providing an “An” class as well so that you can write the more grammatically correct “An<object>.Ignored” rather than “A<object>.Ignored”, but I’m not sure it’s worth it, maybe it’s confusing, what do you think?</p>
<p>I’ll be blogging about argument validations and how to provide your own extension super easy soon.</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:fe669587-1053-4d26-abf4-a30802a55427" class="wlWriterEditableSmartContent">Technorati-taggar: <a href="http://technorati.com/tags/TDD" rel="tag">TDD</a>,<a href="http://technorati.com/tags/fake" rel="tag">fake</a>,<a href="http://technorati.com/tags/mock" rel="tag">mock</a>,<a href="http://technorati.com/tags/stub" rel="tag">stub</a>,<a href="http://technorati.com/tags/C%23" rel="tag">C#</a>,<a href="http://technorati.com/tags/.net" rel="tag">.net</a></div> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-37089267669472253282009-11-07T12:02:00.001+01:002009-11-07T12:02:39.649+01:00Fix that bug will ya? NO!<p>If there’s a bug in software I’ve created my knee jerk reaction is that I created that bug. The knee jerk reaction of some developers is “there must be a bug in the framework”, which of course turns out to be false 99.9999% of the times.</p> <p>Yesterday I managed to track down a bug that had eluded me for a couple of weeks; an object graph that we’re serializing to the Asp.Net session (using state server) sometimes couldn’t be serialized. Every class that could possibly be contained in the graph was marked as serializable and also the error message wasn’t the one you get when you have a value that isn’t serializable in the graph. What I found was the following, we have classes similar to this:</p><pre class="brush: csharp; gutter: false;">public interface IPredicate
{
bool Evaluate(object value);
}
[Serializable]</pre><pre class="brush: csharp; gutter: false;">public class AtLeastPredicate
: IPredicate
{
private IComparable lowerBound;
public AtLeastPredicate(IComparable lowerBound)
{
this.lowerBound = lowerBound;
}
public bool Evaluate(object value)
{
return this.lowerBound.CompareTo(value) <= 0;
}
}
</pre>
<p>You’d think that you’d be able to serialize instances of the AtLeastPredicate-type right? As long as the “lowerBound” value it self is serializable you say. Yup, that should be it I say.</p>
<p>Let’s try that:</p><pre class="brush: csharp; gutter: false;">public class Program
{
public static void Main(string[] arguments)
{
var atLeastString = new AtLeastPredicate("bar");
atLeastString = SerializeAndDeserialize(atLeastString);
Debug.Assert(atLeastString.Evaluate("foo"));
}
public static T SerializeAndDeserialize<T>(T value)
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, value);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
</pre>
<p>Yup, works like a charm as it should. So… What’s the problem? Well, let’s try that again:</p><pre class="brush: csharp; gutter: false;">public class Program
{
public static void Main(string[] arguments)
{
var atLeastInt = new AtLeastPredicate(5);
atLeastInt = SerializeAndDeserialize(atLeastInt);
Debug.Assert(atLeastInt.Evaluate(10));
}
public static T SerializeAndDeserialize<T>(T value)
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, value);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
</pre>
<p>Not much difference there, we’ve changed from comparing strings to comparing ints, and of course ints are serializable too so there should be no problem. But there is, this code will fail:</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikjXN8-cCZvX9bPNUeL0nk9xPf3ClsC-Kippz96LMPgnbtSElt3wS_3cfaFrMj3-Ww7-iR5NO3FnJMJERte5NbtkeWsJGjwwYOj0Ph4Ah_MS9PhDsbGKFRWB9d0BmdGUDnL6Z2zODDkvU/s1600-h/image%5B10%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRqSB7ERh0ntX0lIzm_SSRV-o9ykwOthe3a-p85KpoMlYQQcXm-9pxmjBZ_TRSEl5irxuzfSOk9rEQMf_q7TGwk9sJ3eLZRhZBioRLmpRJdTLUiVX0NoHLfD9xE97bZ_6ogqRpo7yTmZ4/?imgmax=800" width="244" height="133"></a> </p>
<p>Turns out that this <strong>is a bug</strong> in the .net framework:</p>
<p> <a title="http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=91177" href="http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=91177">http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=91177</a> </p>
<p>Oh, well, I’ve created my share of bugs in my life so who am I to blame MS for doing that every once in a while. What I don’t get though is that this bug will not be fixed, I can’t really come up with a scenario where fixing this is a breaking change. Now, for sure, me not being able to come up with such a scenario doesn’t mean it doesn’t exist.</p>
<p>I created an easy workaround for this however and since I was going to use it in a couple of places I encapsulated it in a class of its own:</p><pre class="brush: csharp; gutter: false;">[Serializable]
public class SerializableComparableField
: IComparable
{
private object valueField;
public SerializableComparableField(IComparable value)
{
this.Value = value;
}
public IComparable Value
{
get
{
return (IComparable)this.valueField;
}
set
{
this.valueField = value;
}
}
public int CompareTo(object obj)
{
return this.Value.CompareTo(obj);
}
}
</pre>
<p>Using this class in the AtLeastPredicate and anywhere else we need a field continaing IComparables that should be serializable.</p><pre class="brush: csharp; gutter: false;">[Serializable]
public class AtLeastPredicate
: IPredicate
{
private SerializableComparableField lowerBound;
public AtLeastPredicate(IComparable lowerBound)
{
this.lowerBound = new SerializableComparableField(lowerBound);
}
public bool Evaluate(object value)
{
return this.lowerBound.CompareTo(value) <= 0;
}
}
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com1tag:blogger.com,1999:blog-804807863784809914.post-16015531356547970262009-11-01T12:39:00.001+01:002009-11-01T12:39:02.859+01:00Configuring fake objects on a global scale<p>In this post I’ll describe a way that lets you specify default configurations for specific types so that any time a fake of that type is created this default configuration will be applied.</p> <p>In <a title="The FakeItEasy project at Google Code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a> there’s a concept called a fake object container represented by the interface IFakeObjectContainer which has two methods, one for resolving/creating fakes and one for configuring fakes, in this post I’m going to focus on the configuration part.</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Api
{
using System;
using System.Collections.Generic;
/// <summary>
/// A container that can create fake objects.
/// </summary>
public interface IFakeObjectContainer
{
/// <summary>
/// Creates a fake object of the specified type using the specified arguments if it's
/// supported by the container, returns a value indicating if it's supported or not.
/// </summary>
/// <param name="typeOfFakeObject">The type of fake object to create.</param>
/// <param name="arguments">Arguments for the fake object.</param>
/// <param name="fakeObject">The fake object that was created if the method returns true.</param>
/// <returns>True if a fake object can be created.</returns>
bool TryCreateFakeObject(Type typeOfFakeObject, IEnumerable<object> arguments, out object fakeObject);
/// <summary>
/// Applies base configuration to a fake object.
/// </summary>
/// <param name="typeOfFakeObject">The type the fake object represents.</param>
/// <param name="fakeObject">The fake object to configure.</param>
void ConfigureFake(Type typeOfFakeObject, object fakeObject);
}
}</pre>
<p>Using the <a title="Description of fake scopes." href="http://ondevelopment.blogspot.com/2009/09/fake-scopes-explained.html" target="_blank">scoping feature</a> you can actually plug in your own container for a given scope like this:</p><pre class="brush: csharp; gutter: false;">using (Fake.CreateScope(new MyOwnContainer()))
{
}
</pre>
<p>This means that within this scope your container will be used. Let’s focus on the ConfigureFake-method. This method will be called ANY time a fake object is created by <a title="The FakeItEasy project at Google Code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a> and lets us hook into the creation process and apply configuration to the generated fake object. This provides an easy way of defining default configuration for fakes of certain types which allows you to in your tests focus on configuring the values that are significant to the test.</p>
<p>At the moment the default container is a class called NullFakeObjectContainer, which I’m sure you can guess does exactly nothing. However, there is an assembly distributed in the latest versions named FakeItEasy.Mef.dll. If you in your test-project adds a reference to this assembly <a title="The FakeItEasy project at Google Code." href="http://code.google.com/p/fakeiteasy/" target="_blank">FakeItEasy</a> will automatically pick this up and use the MefContainer as the default container. And this is where the fun begins.</p>
<p>The <a title="MEF on CodePlex." href="http://www.codeplex.com/MEF" target="_blank">MEF</a> assembly exposes two types that are significant to this feature, the most important one being IFakeConfigurator and the most used one being FakeConfigurator<T>.</p><pre class="brush: csharp; gutter: false;">namespace FakeItEasy.Mef
{
using System;
using System.ComponentModel.Composition;
/// <summary>
/// Provides configurations for fake objects of a specific type.
/// </summary>
[InheritedExport(typeof(IFakeConfigurator))]
public interface IFakeConfigurator
{
/// <summary>
/// The type the instance provides configuration for.
/// </summary>
Type ForType { get; }
/// <summary>
/// Applies the configuration for the specified fake object.
/// </summary>
/// <param name="fakeObject">The fake object to configure.</param>
void ConfigureFake(object fakeObject);
}
}
</pre>
<p>As you see this interface is tagged with the InheritedExportAttribute from <a title="MEF on CodePlex." href="http://www.codeplex.com/MEF" target="_blank">MEF</a>, which means that when you implement this interface in a type that type is automatically exported.</p>
<p>As I said the most used one is probably FakeConfigurator<T> which is a base implementation of this interface that lets you implement it very easily. Let’s say for example that you want to provide a common configuration for the HttpRequestBase type, all you do is create a class that inherits FakeConfigurator<HttpRequestBase> and by magic this is exported by <a title="MEF on CodePlex." href="http://www.codeplex.com/MEF" target="_blank">MEF</a> and included in the default container.</p><pre class="brush: csharp; gutter: false;">public class RequestConfiguration
: FakeConfigurator<HttpRequestBase>
{
public override void ConfigureFake(HttpRequestBase fakeObject)
{
Configure.Fake(fakeObject)
.CallsTo(x => x.Form)
.Returns(new NameValueCollection());
Configure.Fake(fakeObject)
.CallsTo(x => x.UserAgent)
.Returns("Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13");
Configure.Fake(fakeObject)
.CallsTo(x => x.ContentEncoding)
.Returns(Encoding.UTF8);
Configure.Fake(fakeObject)
.CallsTo(x => x.Url)
.Returns(new Uri("http://foo.com/"));
Configure.Fake(fakeObject)
.CallsTo(x => x.RawUrl)
.Returns(x => ((HttpRequestBase)x.FakedObject).Url.AbsoluteUri);
Configure.Fake(fakeObject)
.CallsTo(x => x.UrlReferrer)
.Returns(new Uri("http://bar.com/"));
}
}
</pre>
<p>Now any time you create a faked HttpRequestBase it will automatically be configured with this default configuration and you will only have to override this default configuration with specific values you need for your tests.</p><pre class="brush: csharp; gutter: false;">[TestFixture]
public class Tests
{
[Test]
public void Test_something_that_is_dependent_on_the_UserAgent()
{
var request = A.Fake<HttpRequestBase>();
Console.Write(request.UserAgent); // Will print "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13"
Configure.Fake(request)
.CallsTo(x => x.UserAgent)
.Returns("some other agent");
Console.Write(request.UserAgent); // Will print "some other agent"
}
}
</pre> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0tag:blogger.com,1999:blog-804807863784809914.post-40600313463098442972009-10-24T21:22:00.001+02:002009-10-24T21:22:36.302+02:00Asserting on exception messages in NUnit<p>It seems to me that a lot of developers has missed the fact that Assert.Throws<T> in NUnit actually returns the thrown exception which lets you assert on the message (and other properties of the exception). I wrote a response to a question on Stack Overflow which talks about this:</p> <p><a title="http://stackoverflow.com/questions/1609536/nunit-assert-throws" href="http://stackoverflow.com/questions/1609536/nunit-assert-throws">http://stackoverflow.com/questions/1609536/nunit-assert-throws</a></p> Patrik Hägnehttp://www.blogger.com/profile/09722697680972465898noreply@blogger.com0