One of the benefits of adopting WPF Attached Behaviour to adding a dynamic behaviour to WPF controls is that you could unit test the implementation and still use MVVM.
The idea of this post is to demonstrate how to setup and run tests for a attached behaviours. This testing is for the implementation covered in an earlier post. It seemed to me testing is the next natural thing to talk about. Ideally the implementation of the attached behaviour can be split into smaller more responsible classes. You could argue the following tests are more of an integration tests rather than unit tests. You can always do extra refactoring but for the purpose of learning i believe that’s good enough.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
[TestClass] public class DynamicColumnBehaviorTest { private DynamicColumnBehavior dynamicBehavior; private XamDataGrid xamDataGrid; private FieldLayout fieldLayout; #region Setup [TestInitialize] public void TestInitialise() { this.dynamicBehavior = new DynamicColumnBehavior(); this.xamDataGrid = new XamDataGrid(); this.fieldLayout = new FieldLayout(); this.xamDataGrid.FieldLayouts.Add(fieldLayout); } private void SetupBehaviour() { BehaviorCollection behaviors = Interaction.GetBehaviors(this.xamDataGrid); behaviors.Add(this.dynamicBehavior); } private ObservableCollection<OrderViewModel> GenerateDataRows(int rowsCount) { //Relying on the same dummy provider used in Demo App return new MockViewModelProvider().GenerateOrders(rowsCount); } #endregion #region Tests [TestMethod] public void GivenColumnsPropertyChanged_WhenNoOrderItems_ThenColumnsAreNotPopulated() { //Arrange SetupBehaviour(); //Act dynamicBehavior.Columns = new ObservableCollection<OrderViewModel>(); //Assert Assert.AreEqual(0, fieldLayout.Fields.Count); } [TestMethod] public void GivenDataGridIsEmpty_WhenColumnsPropertyChanges_ThenColumnFieldsArePopulated() { //Arrange SetupBehaviour(); var orderViewModels = GenerateDataRows(1); //Act dynamicBehavior.Columns = orderViewModels; //Assert int expectedColumns = orderViewModels.Select(a => a.OrderItems).Max(a => a.Count); Assert.AreEqual(expectedColumns, fieldLayout.Fields.Count); } [TestMethod] public void GivenPrepopulatedDataGrid_WhenColumnsPropertyChangedWithNoRows_ThenZeroGridFields() { //Arrange SetupBehaviour(); this.fieldLayout.Fields.Add(new Field("hello")); //Act this.dynamicBehavior.Columns = new ObservableCollection<OrderViewModel>();//New value //Assert Assert.AreEqual(0, fieldLayout.Fields.Count); } [TestMethod] public void GivenDataGridWithInvalidFieldLayout_WhenColumnsPropertyChanged_ThenColumnsNotPopluated() { //Arrange SetupBehaviour(); this.xamDataGrid.FieldLayouts.Clear(); //Act this.dynamicBehavior.Columns = GenerateDataRows(1); //Assert Assert.AreEqual(0, fieldLayout.Fields.Count); } #endregion } |
Alternate Binding
Unit testing the binding string probably is the most important bit to test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#region Field Creation Binding /* The objective is also to test the Field creation binding code. Ideally such code is pushed to single responsiblity class. */ [TestMethod] public void GivenCreatingDynamicColumns_WhenFieldIsCreated_ThenFieldBindingPathMatchesCellIndex() { //Arrange SetupBehaviour(); //Act dynamicBehavior.Columns = GenerateDataRows(1); //Assert var field = this.fieldLayout.Fields.FirstOrDefault(); var expectedFirstItemBindingPath = "OrderItems[0].Name"; var alternateBindingPath = (field.AlternateBinding as Binding).Path.Path; Assert.AreEqual(expectedFirstItemBindingPath, alternateBindingPath); } #endregion |