It doesn't matter how much we try to avoid it, it is unavoidable. Re-inventing wheel phenomena is always going to take place here and there. Doing a little BDD tests made it clear that I need to mark and specification with the type of the the system under tests I am testing, or the Concern of the test. One way I was showed to do it was to introduce a custom ConcernAttribute and mark with it the TestFixute - specification. Code looks like this:
1: public class ConcernAttribute : Attribute
2: { 3: public Type SystemUnderTestType { get; private set; } 4: public string Message { get; private set; } 5:
6: public ConcernAttribute(Type systemUnderTestType, string message)
7: { 8: SystemUnderTestType = systemUnderTestType;
9: Message = message;
10: }
11:
12: public ConcernAttribute(Type systemUnderTestType) : this(systemUnderTestType, string.Empty) {} 13: }
Not the smartest code in the world, but does it's work:
[Concern(typeof(CurrencyConverter))]
[TestFixture]
public class when_bla_bla_bla
Apperently, MbUnit creators have had this idea before, and where kind enough to create an attribute for this purpose - TestsOnAttribute:
[TestsOn(typeof(CurrencyConverter))]
[TestFixture]
public class when_bla_bla_bla
Wheel re-invention :)
Now why would you prefer to use the original wheel? Well, personally just to save this step from occurring each time...

I wanted to put a simple test in place to document the behaviour of a value converter WPF application I am working on is using. First I did it the standard TDD way (sort of spiking multicultural support of MbUnit framework). The result worked great.
1: [Concern(typeof (CurrencyConverter))]
2: [TestFixture]
3: public class when_converting_with_CurrencyConverter
4: { 5: [Test]
6: [MultipleCulture("en-US,fr-CA")] 7: public void should_format_to_currency_using_current_culture_with_no_decimals()
8: { 9: var value = 2000d;
10: IValueConverter sut = new CurrencyConverter();
11: var result = sut.Convert(value, null, null, Thread.CurrentThread.CurrentCulture);
12:
13: result.ShouldBeEqualTo(value.ToString("C0")); 14: }
15: }
The MultiCultureAttribute was very handy and it did not report the single test as 2 tests in the headcount (having same thing done with RowTest would count test for two, or actually for each RowAttribute applied along with RowTestAttribute).
Now I wanted this to be expressed in a BDD style, since BDD makes more sense from both readability and maintainability perspectives. The code looked like:
1: [Concern(typeof (CurrencyConverter))]
2: [TestFixture]
3: public class when_converting_with_CurrencyConverter : SpecificationContext<IValueConverter>
4: { 5: private double value;
6: private object result;
7:
8: protected override IValueConverter EstablishContext()
9: { 10: value = 2000d;
11: return new CurrencyConverter();
12: }
13:
14: protected override void BecauseOf()
15: { 16: result = sut.Convert(value, null, null, Thread.CurrentThread.CurrentCulture);
17: }
18:
19: [Test]
20: [MultipleCulture("en-US,fr-CA")] 21: public void should_format_to_currency_using_current_culture_with_no_decimals()
22: { 23: result.ShouldBeEqualTo(value.ToString("C0")); 24: }
25: }
Unfortunately this failed. Reason - EstablishContext() and BecauseOf() are both executed upon SetUp of the TextFixture. Therefore the sut being created is there for both tests - with the first culture (en-US).
Listing of the SpecificationContext<T> base class:
1: [TestFixture]
2: public abstract class SpecificationContext<SystemUnderTestType>
3: { 4: protected SystemUnderTestType sut;
5:
6: [SetUp]
7: protected void Setup()
8: { 9: sut = EstablishContext();
10: BecauseOf();
11: }
12:
13: [TearDown]
14: protected virtual void Cleanup(){} 15:
16: protected abstract SystemUnderTestType EstablishContext();
17: protected abstract void BecauseOf();
18: protected TypeToStub Stub<TypeToStub>()
19: { 20: return MockRepository.GenerateStub<TypeToStub>();
21: }
22: protected TypeToMock Mock<TypeToMock>()
23: { 24: return MockRepository.GenerateMock<TypeToMock>();
25: }
26:
27: }
As you can see, the problem is that for both cultures the test is running with only once executed Setup, where the context is established and reason for test is created.
One way to solve it is to split the TestFixute into to. I am not likely to prefer this due to the fact that it defeats the purpose of testing - simple and quick. Another way, the one I will probably implement, is revert from BDD to classic TDD.
Although this is what I've decided for this particular test, this does have implications on other UI testing where multicultural support is important. In case any of you my dear readers has run into similar situation and managed to figure out a solution for BDD way, please share your experience.
I am a total newbie in WPF development. One of the things I wanted to have is to format the values coming out of my domain object into UI, and being able to parse those values back into business objects.
I am coming from a web environment, where no state exists in between requests. I started with an approach usually apply in the web applications, quickly realizing it will not work that way. The fact that DataContext (like a ViewData) is there and doesn't have to be reconstructed is great. The down side - it's not strongly typed. At the same time maybe the only way to use it is one, when assigning the data(object) and that's it. Also bugging the fact that the properties are used for binding as string texts, but that I have to understand better.
Since the DataContext is going nowhere, and it's a reference to domain object, DataBinding done in TwoWay mode (which is the default) assures that any change (as long as it is valid) will propagate back into the domain object (it's property). Converters are another piece of this not so trivial puzzle - they make life easy. By implementing IValueConverter, it is possible to implement the logic for value transformations upon each way of binding. Handy, since it allowed me to decorate currency attributes of my domain object to show currency details on UI, and strip that off and get a plain number when taking the currency value back into the domain object.
The XAML way - not sure I like it completely at this stage. Being able to express binding and converter for the binding in a codeless way is nice. The facts that:
- You have to create a static resource on each "view" (window/user control) did not sound well
- The loose control over the binding gives you now firm understanding of what's going on behind the scene
So I started to poke around the idea of using a single converter all over the place. And found it. Again, declaratively, it was a mess, since WPF XAML parse had an issue with it, even though it was compiling. Pure code approach was simple, and XAML parser did not complain.
I put converter into a single location where it can be used by any "view" and it looked like this:
namespace WpfApplication1
{
public static class Converters
{
public static CurrencyConverter CurrencyConverter = new CurrencyConverter();
}
}
And the code that was doing binding looked like the following snippet:
var binding = new Binding("Amount");
binding.Source = myObject;
binding.Converter = Converters.CurrencyConverter;
txt.SetBinding(TextBox.TextProperty, binding);
The declarative way looked uglier:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Text="{Binding Path=Amount, Converter={x:Static app:Converters.CurrencyConverter}}"
Height="20" Width="100"></TextBox>
<Button Grid.Row="1" Name="btn" Height="20" Content="Report value"></Button>
</Grid>
</Window>
The currency converter is dead simple:
namespace WpfApplication1
{
[ValueConversion(typeof(double), typeof(string))]
public class CurrencyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((double) value).ToString("C2", culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
double result;
double.TryParse(value.ToString(), NumberStyles.Currency, culture, out result);
return result;
}
}
}
Thoughts, comments, sources for more information are more than appreciated.
Issues are:
- Constant requirement to defrag the VSS database
- Loosing checked in code
- Merging is absolute on block, and not partial merging
- VSS client for VS.NET sucks, when getting latest version and focus away, the VSS dialog box hangs, along with VS.NET itself
- Deleting checked out files leaves them on server
- Checking in files that were touched, but final result was not different from original (1)
- Patching?
What did you find that I didn't list here? Help me to convince my good fellow coworkers to move away from the beast. Thank you.
(1) Checked out file for change and reverted change to original code (i.e. file has not changed)