Search This Blog

Tuesday, April 10, 2012

Flex: unittest a view with radio buttons

At a recent project where I do some coaching, we wanted to unit test the validation logic present in view components. The validation logic is implemented as an array of validators which are triggered after some specific events take place. To test this we basically did the following:

  1. Created a unit test (we are using FlexUnit)
  2. Instantiate and initialize the view in the unit test
  3. Populate the UI components with values to test
  4. Trigger the validators
All seems well until we wanted to populate the selectedValue property of a RadioButtonGroup. This did not seem to work from within our unit tests. According to the documentation the selectedValue property can both be set and read from within code. Testing this logic inside a standalone MXML component and setting the selectedValue property did work. Unfortunately this did not help in our unit test because there it did not work.

Looking at the source code of the RadioButtonGroup I noticed that when setting the selectedValue property, the code loops over the associated RadioButtons. In our unit test the associated RadioButtons are not set (I expected that they were set actually). After digging some further I noticed the addInstance(instance:RadioButton):void method. This method apparently adds a RadioButton to the RadioButtonGroup. But where is it called? Somewhere by the Flex framework but where exactly was not obvious. Notice that this method is declared in the mx_internal namespace which means that this functionally may change in a future release. It also means however that we can still call this code ourselves.

To fix our test, the mx_internal namespace is added so the addInstance method can be called from within the test. With the addInstance method all RadioButtons which belong to the RadioButtonGroup can be added to the group. See the example below.

   1:  <?xml version="1.0"?>
   2:  <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
   3:      <mx:RadioButtonGroup id="genderRadioButtonGroup"/>
   4:   
   5:      <mx:RadioButton id="male" groupName="genderRadioButtonGroup" label="male"></mx:RadioButton>
   6:      <mx:RadioButton id="female" groupName="genderRadioButtonGroup" label="female"></mx:RadioButton>
   7:  </mx:VBox>

And the code of the unit test:
   1:  package {
   2:  import flexunit.framework.TestCase;
   3:   
   4:  import mx.core.mx_internal;
   5:   
   6:  use namespace mx_internal;
   7:   
   8:  public class RadioButtonTest extends TestCase {
   9:      public function RadioButtonTest() {
  10:      }
  11:   
  12:      public function testPopulateRadioButton():void {
  13:   
  14:          var myForm:MyForm = new MyForm();
  15:          // Initialize the UI component so that all child components are added to the form.
  16:          myForm.initialize();
  17:   
  18:          // Explicitly add the radiobuttons to the group, please note the use namespace mx_internal or else this
  19:          // method can not be called.
  20:          myForm.genderRadioButtonGroup.addInstance(myForm.male);
  21:          myForm.genderRadioButtonGroup.addInstance(myForm.female);
  22:   
  23:          myForm.genderRadioButtonGroup.selectedValue = "male";
  24:   
  25:          assertEquals("male", myForm.genderRadioButtonGroup.selectedValue);
  26:      }
  27:  }
  28:  }

Conclusion
Using the mx_internal namespace is not encouraged but sometimes can help to work around certain limitations, especially in test code. In the case of the RadioButtonGroup I would assumed things worked differently but unfortunately they did not. I doubt that this will be fixed in a future release regarding the state of Flex at the moment.

If you have another solution to the above problem please share it!