|
Project Information
|
A Poem on XAMLWe programmers, as you know, have malformed brains.
Most of the time we tend to think like engineers, but if you give a regular engineer a new tool, the engineer will say "Thank you for this interesting tool. I will keep it in mind if a problem arises that seems to require it." A programmer, on the other hand, given a tool like XAML,
starts to think: "This is very cool. I wonder what I can do with this in the absence of all other tools. What it would be like to live on Planet XAML? How would I move around? What would I eat? How would I procreate? And if the only tool I have is XAML, what do the problems look like?" Charles Petzold OriginsWhere'd Cowbell come from?The name of the project comes from the Saturday Night Live skit Behind The Music: Blue Oyster Cult. In the words of Christopher Walken, we encourage WPF developers to Explore The Space. As the leader of this project, I am focused solely on getting More Cowbell onto XAML projects. Community InvolvementEasy, guys.. I put my pants on just like the rest of you - one leg at a time. Except, once my pants are on, I make gold records. Christopher Walken, as Bruce Dickinson That's a great idea, send me a patchThere is no shortage of people with crazy ideas. I need people who can execute. The scope of this project is small, and contributions should be easy to make. Step 1. Derive from MarkupExtension Step 2. Override ProvideValue LURR Principle (Listen, Understand, Respond, Repeat)Public API design is a difficult task. Here is a recipe that I've found works: Step 1. Listen. Pay attention to what others tell you. Step 2. Understand. Step 3. Respond. Step 4. Repeat. Continue listening, understanding, and responding. Full Source and Opt-in Knowledge SharingSome projects license source code to programmers with a "some source is better than none" policy. A read-only license only benefits a small group of people. A read-only license does not help the project and does not help its client programmers, because it discourages knowledge sharing. There is a better way. Publishing patches to the project prevents teams from fixing the same problems over and over again. Problem AnalysisXAML Use Case and ScenariosXAML is for describing hierarchies of objects, and serves as the lingua franca between .NET designers, .NET developers and .NET code generators. It is used by WPF and WF, but also usable for arbitrary scenarios within .NET when describing a hierarchy of objects. XAML Parsing is Unique Compared to Plain Old XMLPlain Old XML is parsed top-down using recursive-descent parsing. XAML, on the other hand, is parsed top-down by default and can be parsed bottom-up by nesting MarkupExtension elements. Once a recursive-ascent parsing pass is complete, another recursive-descent pass begins. You can think of it as Packrat Parsing. The Design of WPF Dependency PropertiesWesner Moise's .NET Undocumented has a cool write-up on [DependencyProperty] Using a MarkupExtension versus an Attached PropertyUsing a MarkupExtension can obfuscate a XAML document. However, a MarkupExtension gives you flexibility beyond what an Attached Property can give you. In particular, using recursive-ascent parsing to remove boiler plate required by recursive-descent parsing. The goal is to simplify XAML and make XAML more powerful; if a lot of elements use the same raw materials, then a MarkupExtension can aggregate those raw materials into a single logical block of markup. For instance, a MarkupExtension can even be used to aggregate several Attached Properties. Also, an Attached Property cannot be applied to a non-Dependency Object. e.g. // This is clearly NOT a dependency object.
public class SubscriptionExtension : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
...
}
}
<!-- LocalStateVariable.GroupName requires that SubscriptionExtension be a dependency object -->
<Subscription SubType="sys:String"
DataItemName="Test_String"
SamplingRate="5"
LocalStateVariable.GroupName="Test_Group"
LocalStateVariable.SaveAsBinary="False"/>Namespace LayoutI would like to follow the namespace conventions Microsoft uses for its XAML parser. In particular, the notion that MarkupExtensions should be in a Markup namespace like System.Windows.Markup: namespace Cowbell.Iconic // for Icon Programming Language inspired features namespace Cowbell.Frozen.Markup namespace Cowbell.Bandaids namespace Cowbell.Bandaids.Silverlight.VersionX.Markup namespace Cowbell.Bandaids.WPF.VersionX.Markup Applying a View to a ViewModelA view consumes a ViewModel's functionality. {Apply vw:AllCustomersView, To=vw:AllCustomersViewModel}or, more verbosely, {Apply Template=vw:AllCustomersView, To=vw:AllCustomersViewModel}transforms into Josh Smith's code example: <!--
This template applies an AllCustomersView to an instance
of the AllCustomersViewModel class shown in the main window.
-->
<DataTemplate DataType="{x:Type vm:AllCustomersViewModel}">
<vw:AllCustomersView />
</DataTemplate>See figure 10 from Josh Smith's article WPF Apps With The Model-View-ViewModel Design Pattern Generic Programming in XAMLGeneric programming is a powerful programming style defined by a set of design constraints. Out-of-the-box, XAML does not lend itself well to generic programming. For instance, by default, each XAML markup element maps to a CLR object element. Thus, by default, an interface cannot be an XAML markup element. The solution is to create a generic ClassFactory MarkupExtension class. See Rob Relyea's tutorial MarkupExtension As An Object Element: ClassFactoryExtension.
J.C. Dehnert and Alexander Stepanov, Fundamentals of Generic Programming
Ideas for Generic Programming Against MarkupExtension-derived ClassesXAML BugsYou cannot nest a StaticResource or DynamicResource within a custom MarkupExtension when using Attribute Syntax. cowbell:Markup Source={StaticResource myResource} will result in a XamlParseException. The workaround is to nest a StaticResource or DynamicResource using Property Element Syntax. Finding Memory Leaks in WPF Based Applications by Jossef Goldberg Got performance issues? Check our Kiran's Definitive Guide to WPF Performance Issues This section is intended to point out bugs in the XAML parser. For help debugging your XAML code, see Debugging and Interpreting Errors in the WPF Designer. Daniel Paull has pointed out to me that there is a bug in how whitespace is parsed. You currently can't apply xml namespace attributes to property elements (lame). (I hadn't thought of this concept, either, and it's really cool.) Abstracting Boiler plateIn Windows Presentation Foundation Unleashed, Adam Nathan demonstrates the WPF Command infrastructure: <Window x:Class="WPFWinApp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPFWinApp" Height="300" Width="600">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Button Command="Cut" CommandTarget="{Binding ElementName=tb1}" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />
<Button Command="Copy" CommandTarget="{Binding ElementName=tb1}" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />
<Button Command="Paste" CommandTarget="{Binding ElementName=tb1}" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />
<Button Command="Undo" CommandTarget="{Binding ElementName=tb1}" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />
<Button Command="Redo" CommandTarget="{Binding ElementName=tb1}" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Enter some text: </Label>
<TextBox x:Name="tb1" Width="200" />
</StackPanel>
</StackPanel>
</Window>It would be nice to have a CommandButton MarkupExtension that simplified the creation of a Button whose sole purpose in life is to invoke the functionality of another control. Something like: <CommandButton Command="Edit" CommandTarget="nameOfElement" Style="{DynamicResource buttonStyle}"/>By default, cowbell could use ElementName binding. This could be simplified further if Cowbell maintains two MarkupExtension library namespaces, one for Controls with dynamic styling and another for Controls with static styling. e.g.: <?Mapping XmlnsNamespace="cowbelldynamic" ClrNamespace="clr-namespace:Cowbell.Dynamic" Assembly="Cowbell" ?> <cowbelldynamic:CommandButton Command="Edit" CommandTarget="nameOfElement" Style="buttonStyle"/> Behind the scenes, cowbell generates calls to DynamicResource markup extension and Binding ElementName, Binding RelativeSource, and automatically applies the text "Edit" as the content of the button. XAML QuestionsHow can I model suspension of evaluation in XAML, like Icon has?
Most programming languages resolve this "ambiguity" by producing the first (left-most) position. On the other hand, a computation may need to be performed on all positions. If only one is produced, it is necessary to "work around" the one-value limitation by forming substrings and searching for the positions in a loop. The Icon function find(s1,s1) illustrates the usefulness of producing more than one result. It generates the positions at which s1 occurs in s2. It produces the first position and suspends. If another position is needed find(s1,s2) is resumed to produce another position. If there are no more positions, find(s1,s2) fails when it is resumed (as it does initially if there is no position). Encyclopedia of Microcomputers by Allen Kent, James G. Williams, Rosalind Kent, Carolyn M. Hall XAML IdeasUsing expression trees in C# 3.0 to create hygienic macros. Open question: Does XAML out-of-the-box have a "bread crumbs" invocation code smell? e.g. Obj1.Obj2.Obj3 A common way to approach the "bread crumbs" invocation code smell in OO languages is to do proper modeling and make effective use of polymorphism, such that the code that executes is a delegate. Someone made an observation regarding memory leaks in the comments of Bea Costa's blog entry How should I data bind a Polygon’s Points to a data source? - Part III. He points out the problem with having a value converter defined as a static resource that ultimately stores state for multiple bindings: You don't know when you no longer need that memory. In my humble opinion, value converters should just be pattern matchers and therefore not store any state. Instead, the objects that they pattern match against should store the state. Or, more realistically, a mediator like Binding should store the transient state using a Memento design pattern. Does anyone agree or disagree? The reason I bring this up is that I am trying to think of how I can write a MarkupExtension that is the moral equivalent of C++ Boost smart pointers. See Tomer Shamam's WPF Control State Persistency for ElementStateExtension, which uses a MarkupExtension as an attached property and as an attribute value. I was wondering if this was possible, and seeing it done has me very excited. A Fun MarkupExtension for specifying Functions: {Fun Return={SomeMarkupExtension args}, Call="{Lambda}"}A Yield MarkupExtension for generator an enumerable collection. An Enumerator MarkupExtension for returning an enumerable collection. {Enumerator Value={Fun Return={SomeMarkupExtension args}, Call="{Lambda}"}
{Enumerator Value={Yield {Lambda}}}Michael Latta critcizes XAML: "XAML timelines can only affect properties, not the actual layout of the XAML file itself. You can not say after this happens add these three TreeViews to this page just there. You can make ones you anticipated in the XAML visible, but not create new ones. For that you need imperative code. In WPF this is C#." To be fair, I don't think Michael is entirely correct. It is not obvious how to specify XAML timelines, but possible. In the comments, William Kempf notes: "Content can be created via triggers... by changing the template." ExecutablePanel that extends Panel and adds an Execute method that populates its Children at run-time. Client programmer must call this in the Page.Load method. This will allow faster processing of the XAML document by avoiding bottlenecks like waiting for resources. ExecutablePanel exePanel = Resources["myExePanel"]; exePanel.Execute(); Testable Resources that are coalesce duplicate elements of many tested components (see Set MarkupExtension) Exploring using XML Entity Declarations as a forward-reference macro system. See ENTITY Declaration Using XAML to bootstrap testing. William C. Wake's Arrange-Act-Assert test pattern can be specified using a recursive-descent/recursive-ascent/repeat strategy rather than a procedural strategy. Shawn Wildermuth discusses how the core WPF team at Microsoft thinks about XAML Control Design, and he mentions that they use a Create-Set-Use Pattern to designing XAML controls. See also: Learning and Craftsmanship which discusses Act/Arrange-Assert's cousin the Four-Phase test. See also: Fitnesse's Build-Operate-Check pattern See if it is possible to model Inheritance of Failure (as seen in the Icon Programming Language) in XAML using recursive-ascent parsing.
A Set MarkupExtension that takes a Collection of Children and returns a Collection consisting of elements in the Set (removing duplicates). A MacroXAML MarkupExtension for treating XML as a hierarchical function parameter. Explore a MarkupExtension that abstracts the boilerplate from XAML's Markup Compatiblity (mc:) Language Features. XAML uses TypeConverter objects to convert (Brush)TypeDescriptor
.GetConverter(typeof(Brush))
.ConvertFromInvariantString("Yellow")A large library that uses multiple namespaces can take advantage of mapping a namespace URI to multiple namespaces. Most books on WPF don't cover this, but you can do the following: [assembly: XmlnsDefinition("http://code.google.com/p/cowbell/schemas/", "com.google.code.cowbell")]
[assembly: XmlnsDefinition("http://code.google.com/p/cowbell/schemas/", "com.google.code.cowbell.integration")]A MarkupExtension that has a public Property of type MarkupExtension, for the sole purpose of having a generic way to nest MarkupExtensions. Nesting markup elements typically means nesting objects. However, MarkupExtension elements can arbitrarily nest, too, and each stage can provide a different kind of object to operate on. namespace Cowbell
{
public class MarkupMarkExtension : MarkupExtension
{
public MarkupMarkupExtension(MarkupExtension LambdaForm)
{
this.LambdaForm = LambdaForm;
}
[ConstructorArgument("LambdaForm")]
public MarkupExtension LambdaForm
{
get; set;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget ipvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
MarkupExtension fe = ipvt.TargetObject as MarkupExtension;
if (fe != null)
{
return me.ProvideValue();
}
else
{
throw new Exception("Name " + _Name + " is not resolvable because the parent object isn't findable");
}
}
}A MarkupExtension that has a public Property of type List <markupextension>, for the sole purpose of defining a sequence of MarkupExtension transformations. It might be best to design this as MarkupExecute and MarkupEscape, both extending MarkupExtension. almost same as above, except uses a List A Pragma MarkupExtension. In C#, pragma can be used to apply a change from one point in a file going forward. This change can be reverted by issuing another pragma. In XAML, a Pragma could be lexically scoped by the section of the DOM tree it is contained within. Therefore, it automatically rolls itself back. A MarkupExtension called Pairs that constructs a Dictionary. The Pairs MarkupExtension may also use a TypeConverter to define a "mini language". A "mini language" is used by the Path element: <Path Stroke="Black" Thickness="5" Data="M 30,60 Q 50,90 70,60" /> A more complicated TypeConverter can use Property.Element Syntax for scenarios where types are too complex for a "mini language"; properties are themselves objects and can therefore be arbitrarily complex. Also, as Rob Relyea points out in Strings to Things a "mini language" is not extensible, because extending the language would introduce versioning problems. A MultiBinding MarkupExtension and a new IMultiValueConverter interface to replace the horrible design of MultiBinding and IMultiValueConverter in .NET Framework 3.0. See WPF Binding Expression Alternatives for what people have done to improve the basic Binding MarkupExtension. The Blendables library also provides two additional Binding mechanisms: EvalBinding and SimpleBinding with examples. The last thing I want to do is proliferate XAML with a bunch of different Binding MarkupExtensions, like Java's GeoTools Binding implementation. A String MarkupExtension that delegates to the CLR string object. The point of this MarkupExtension is to allow type-safe representation of XML as strings, e.g.: <cowbell:String> <TextBlock Text="Hello World"/> </cowbell:String> would create a CLR String that stores <TextBlock Text="Hello World"/> A Meta and/or Load MarkupExtension that is a delegate for XamlReader.Load(), allowing efficient compilation down to baml. These intermediate transformations are never seen inside the resulting baml, and thus would allow multi-stage programming. A Merge MarkupExtension that can do thinks like merge resource dictionaries, rather than the heavy handed WPF approach of MergedDictionaries. A CodeProject article about creating aggregate views of data by implementing IValueConverter as an aggregate "function object". In the example, an Excel-like Max function is called. This implementation is not good in the reusable sense, because it does not take advantage of monad comprehensions. (My current position on this is that we should also seek to better understand the differences between subtype polymorphisms (single dispatch, double dispatch, multiple dispatch) and set-based feature dispatch.) See also, http://nice.sourceforge.net/visitor.html Visitor Pattern versus Multimethods and Robert Cecil Martin'S I Use Visitor All the Time, and these course notes point out a common use case for the visitor pattern: "The assumption is that you have received a fixed unrelated class hierarchy (from a vendor), which cannot be changed, and you need to add some new functionality to the hierarchy, which means that normally the base class interface needs to be changed.". Visitor Revisited discusses the descriptive flaw in design patterns. and visitor pattern discussion by stan james, and Subject-oriented programming and the visitor pattern; all links via http://www.compwisdom.com/topics/Visitor-pattern See also Catamorphisms, part three As Holub notes, two principles of object-oriented systems are: # Never ask an object for the information you need to do something; rather, ask the object that has the information to do the work for you. # It must be possible to make any change to the way an object is implemented, no matter how significant that change may be, by modifying the single class that defines that object. Ward's Wiki has an article on AlternateHardAndSoftLayers that provides an answer to the question Why Compile Data? One of the contributors discusses the architecture of Quake 3: Arena: "The game logic itself (physics, weapons, scoring, etc) runs atop the engine in a flexible virtual machine. Game code communicates with the engine through system calls or "traps" (there is also a small shared memory segment for high-bandwidth communication). [...] In Quake 3 the game code is written in a dialect of C, and then compiled down to bytecode (which the engine may JIT compile for extra speed). [...] The advantage of this split between engine and game code is that you can swap out the game logic without recompiling the engine." A DynamicDraw MarkupExtension that dynamically draws objects. Idea based on the following Avalon newsgroup posting: Sujet: Dynamically Drawing Objects De: kmattern@araneasolutions.com (kmttern) Groupes: microsoft.public.windows.developer.winfx.avalon Date: 25. Mar 2008, 09:51:16 This should be so simple! I need to generate a bar graph using WPF. It's easy to do with XAML and I have some very nice graphs. But I need to dynamically genenerate the graphs because I do not know before I query the database how many bars I will need. It should be so simple to draw as many rectangles I need and to place them on my canvas. But I can't find anything on how to do it. What few WPF examples I can find on anyting are written in C#. Surely there are Visual Basic users out there as well. OS XP Pro Language VB 2008 Any ideas will be greatly appreciated Ken Dr. WPF's ConceptualPanel/LogicalPanel idea Mike Hillberg's Leveraging Freezables to Provide an Inheritance Context for Bindings - in the comments, Rob Eisenberg points out that Mike's approach is similar to Caliburn's ActionMessage and EventMessage systems. Design Constraints The Inner Dependency Problem Looking at WPF and JavaFX, thinking on SWT: Andrey Platov discusses Apache, academics and freelancers all trying to use Desktop UI APIs to bring the browser to the desktop. Natural way to develop UI: Andrey Platov discusses in a roundabout way why the notion of global styles is wrong, because he points out that the WPF composition-based styling system allows you to define appearance at any level you choose, including the window-level or application-level. Fair Criticism of WPFOccasionally, I come across an article pointing out a flaw in WPF. I will record those articles here:
When a markup extension is used to provide an attribute value, the attribute value should instead be provided by the logic within the backing class for the relevant markup extension.
TextBoxBase exposes a lot of concepts based around this, like a SelectionChanged event, AutoWordSelection and Cut/Copy/Paste based on the selection. However, there's no way to determine what the selection is! TextBox and RichTextBox aren't consistent in how they expose the selection.TextBox exposes SelectionStart and SelectionEnd while RichTextBox exposes a Selection. That's wacky enough to be highly questionable to me. Just bad design. But what's worse is that all of these methods are implemented in terms of a TextSelectionInternal on the base TextBoxBase, which, like the name indicates, is internal! How did this design pass code review?
<TreeView SelectedValue="{Binding Path=Selected, Mode=OneWayToSource}" />
<ItemsControl ItemsSource="{Binding FlattenedTree.Items}"/> private object selected;
public object Selected
{
set
{
this.selected = value;
Changed("FlattenedTree");
}
}
public FlattenedTree FlattenedTree
{
get
{
if (selected == null)
return null;
return new FlattenedTree(selected);
}
}Instead of pushing the selected item back into the model to convert it and send it out again - lets just convert it!
<TreeView Name="TreeView" ItemsSource="{Binding Root.Children}" />
<Grid DataContext="{Binding ElementName=TreeView, Path=SelectedValue,
Converter={x:Static local:FlattenedTreeConverter.Instance}}">
<ItemsControl ItemsSource="{Binding Items}" />
</Grid> public class FlattenedTreeConverter : System.Windows.Data.IValueConverter
{
public static FlattenedTreeConverter Instance
{
get { return new FlattenedTreeConverter(); }
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
return new FlattenedTree(value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}Solving XAML's out-of-the-box violation of the Open-Closed Principle. M. Orçun Topdağı's work on GeoStructor is an inspiration: <Style x:Key='GObjectGeneratorButtonStyle'
TargetType='{x:Type ContentPresenter}'>
<Setter Property='ContentTemplate'>
<Setter.Value>
<DataTemplate>
<Button x:Name='xButton'
Margin='1'
Content='{Binding Attrib.UIName}'
IsEnabled='{Binding IsApplicableToSelection}'
Command='{x:Static g:GEngine.Generate}'
CommandParameter='{Binding}'
ToolTip='{fix:Binding i={Binding IsApplicableToSelection},
b={Binding},
ToTarget="i ? b.Attrib.Description : b.Requirements"}'
ToolTipService.ShowOnDisabled='True' />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>Future of Silverlight?An Interview with Scott Guthrie where he reveals that a future iteration of Silverlight will allow you to view Silverlight applications in the browser or on the desktop on multiple platforms. DeploymentYou don't want to tightly couple your application to the Windows Registry. Jon Galloway points out in his blog that We should be virtualizing applications not machines. I don't totally agree with this. IBM got virtualization right (s/360), Intel/Microsoft got virtualization wrong (MS-DOS); we're stuck with the aftermath. However, he has a key point that shouldn't be overlooked:
My ThoughtsCurrently, I am developing a Silverlight 2 application. Through no choice of my own, I am using XAML. Being forced to use a language has a strange way of forcing you to become an insider and assess the language fairly. Initially, I did not like XAML at all. After using it for three months, it has become familiar and -- surprise -- is now my preferred template language. Funny how adoption works. The question I've been asking myself is, "Was it just a matter of becoming familiar with the language that changed my opinion about it?" I don't think so. I still see major problems with the way Microsoft expects developers to write XAML. My two biggest complaints are that XAML out-of-the-box violates the Open-Closed Principle and promotes Pollution of the Knowledge Space. For instance, if I want to adjust the style of a column header for a DataGrid control, then I have to copy-and-paste a multiple line ControlTemplate off MSDN and edit one line within that ControlTemplate. All I want to do is adjust a Layout Property like VerticalContentAlignment, yet the out-of-the-box way of writing XAML forces me to pollute the Style setter with information unrelated to Layout Properties. In doing so, I have polluted the knowledge space by providing excess details to accomplish the primary objective of the Style setter. These extraneous details are orthogonal concerns that I should not have to worry about at that particular point in time. From what I have seen on the Internet, most criticism of XAML is an ad hominem attack against Microsoft. For instance, they argue that we already have XForms, CSS, XHTML, XUL, SVG and sXBL. From their perspective, it looks like Microsoft is re-inventing the wheel and that XAML is just another weapon for an Embrace, Extend, Extinguish coup d’état. Such a point of view is sad, but a reflection of the fact that Microsoft has continuously changed the standard way of doing things. For synchronization, it used to be Hailstorm and now it is LiveMesh. For database technologies, it has evolved from ODBC to OLE DB to RDO to ADO to ADO.NET. For any given technology Microsoft has touched, there has been disruptive evolution. Yet, in XAML, Microsoft appears to have created something permanent. It is a single, unified language that closely obeys Elliotte Rusty Harold's stringent Effective XML guidelines. The biggest negative is that it is tightly coupled to the CLR; the Application Pack URI format is just one example of its tight integration with Microsoft virtual machine technology. NUnit StuffComparison to org.springframework.util.AssertBuild-Operate-Check and Arrange-Acts-Assert Data Driven TestJUnitJUnit: A Cook's Tour - based on JUnit 3.8.x RowTestAndreas Schlapsi wrote an NUnitExtension called RowTest, which allows NUnit users to write a single unit test to test the same functionality using different values. NUnit 2.4.7 added official support for RowTest Extension as an add-in. The extension resides in the NUnit.Framework.Extensions namespace. The idea for the feature -- a single test method to execute multiple tests with different parameter inputs -- was taken from MbUnit. MbUnit offers RowTest with support for Negative Assertions. [TestFixture]
public class DivisionFixture
{
[RowTest]
[Row(1000,10,100.0000)]
[Row(1,0,0, ExpectedException = typeof(ArithmeticException))]
[Row(-1000,10,-100.0000)]
[Row(1000,7,142.85715)]
[Row(1000,0.00001,100000000)]
[Row(4195835,3145729,1.3338196)]
public void DivTest(double num, double den, double res)
{
Assert.AreEqual(res, num / den, 0.00001 );
}
}MbUnit is a generative unit testing framework. Traditional unit testing frameworks required a single method for each set of test data, resulting in code duplication. This code duplication creates monolithic test fixtures, because the test fixture has N tests where N tests have the same state-process, but expect different outcomes based on different input parameters. MbUnit lifts these input parameters and outcomes into a RowAttribute decorator. Andreas also wrote a tutorial on how to write an NUnit add-in. He also wrote a very persuasive essay, Decorate Your Tests. I would like to see cowbell add support for decorators somehow, possibly mimicking the NUnit way of doing things: an IMarkupExtensionDecorator interface that requires implementing the following signature: public MarkupExtension Decorate(MarkupExtension markupExtension, MemberInfo memberInfo);. Below is how NUnit does it: IExtensionPoint testDecorators = host.GetExtensionPoint( "TestDecorators" );
...
// There is currently no mechanism to control the order in which the decorators are applied.
// NUnit applies decorators in the order in which they are returned through reflection.
// Therefore pay attention to this issue if you use more than one decorator.
public interface ITestDecorator
{
Test Decorate( Test test, MemberInfo member );
}The Gallio test automation platform and the MbUnit unit testing framework Jamie Cansdale: "When using MbUnit, it is common for a single test method to execute multiple tests with different parameter inputs. The most famous of these test types is the MbUnit RowTest." MbUnit also supports PairWise, Repeat and Rollback2. Andrew Stopford notes: PairWise and RowTest will drill across a range of values between x and y. It's really intended to throw a wide net over your tests, you could then combine with code coverage to check you don't have plains of untested code showing up and that your checking for the unexpected in your code. I'd double up with a more directed test to check expected against actual as well as a wide net test so you get the best of both worlds. Rollback allows automatic rollback of database changes by wrapping the changes in a COM+ transaction. Another MbUnit feature is the Provider attribute. Fair Criticism of NUnit
John Gossman on VisualState and Triggers
WPF Team Members on Attached Behaviors
|