Custom test runner for FlexUnit 4 and mock-as3

Brian LeGros | August 6th, 2009 | programming  

At the August Adogo meeting, I presented on the new features coming in FlexUnit4 and mock-as3. During the presentation, I showed the following sample (which has been updated) of how a FlexUnit 4 test using a customer runner for mock-as3 would work. Please keep in mind the example is a bit contrive but exemplifies the configuration options for the runner.

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
package us.adogo.mock
{
   import com.anywebcam.mock.Mockery;
 
   import org.flexunit.Assert;
   import org.flexunit.assertThat;
   import org.hamcrest.core.not;
   import org.hamcrest.object.equalTo;
   import org.hamcrest.object.hasProperty;
   import org.hamcrest.object.nullValue;
 
   [RunWith("com.anywebcam.mock.runner.MockAs3TestRunner")]
   public class ExampleUsingMockAs3Runner {
      public var mockery : Mockery;
 
      [Mock]
      public var user : User;
 
      [Mock(inject="false")]
      public var account : Account;
 
      private var controller : UserController; 
 
      [Before]
      public function setUp() : void {
         account = mockery.nice(Account, ["1234567890"]) as Account;
         this.controller = new UserController(); 
      }
 
      [Test]
      public function testAddUserWithUsernameAndPasswordOnly() : void {
         //setup mock
         mockery.mock(user).method("save").calls(function () : void {
            user.id = 1;
         }).once;
 
         //populate object properties as you usually would
         user.username = "bobdobbs";
         user.password = "mysecret";
 
         //execute my controller method being tested
         controller.addUser(user);
 
         //test that the currentUsers went up by one and that its id is 1
         assertThat(controller.currentUsers.length, equalTo(1));
         assertThat(controller.currentUsers.getItemAt(0).id, equalTo(1));
         assertThat(controller.currentUsers.getItemAt(0).username, equalTo("bobdobbs"));
         assertThat(controller.currentUsers.getItemAt(0).password, equalTo("mysecret"));
      }
 
      [Test]
      public function testValidateUserAccount() : void {
         //setup mock
         mockery.mock(account).method("isValid").withArgs(User).returns(true).once;
 
         //execute my controller method being tested
         var expected : Boolean = controller.validateUser(new User(), account);
 
         //test that the account is valid
         Assert.assertTrue(expected);
      }
 
      [Test(verify="false")]
      public function testDefaultUserSize() : void {
         assertThat(controller, hasProperty("currentUsers"));
         assertThat(controller.currentUsers, not(nullValue()));
         assertThat(controller.currentUsers.length, equalTo(0));
      }
   }
}

This evening I updated the Adogo SVN with a working version of this runner and thought I’d detail its initial implementation.

  • To use the runner place the metadata [RunWith("com.anywebcam.mock.runner.MockAs3TestRunner")] on the test class’ declaration.
  • Once annotated with metadata, the test class will not run unless a public variable, or setter, is available of type com.anywebcam.mock.Mockery. This will allow the runner to inject a Mockery object and prepare() the mockery to produce mock objects. Using and preparing a mockery is a new requirement for mock-as3 if you’re utilizing type-safe mocks due to the asmock integration.
  • Any public variable, or setter, annotated with the metadata [Mock] will have a type safe version of it injected automatically prior to the execution of each test method. By default a nice mock will be used, but if you specify the “type” attribute (e.g. – [Mock(type="strict")]) as “strict” then a strict mock will then be used. The difference between nice and strict mocks, is the equivalent of the “ignoreMissing” constructor argument on com.anywebcam.mock.Mock being set to true, or false, respectively.
  • If the [Mock] metadata is used on a class with a constructor requiring arguments, whether they are optional or …rest, the runner cannot automatically inject the mock due to a limitation in its underlying dependency on the asmock library. If you need a mock object instance using constructor arguments, set the attribute “inject” as false (e.g. – [Mock(inject="false")]. Doing so will tell the runner that you’re going to use the mock-as3 framework directly to create the mock. The ideal place to do this in your test is within the [Before] methods defined for the test class. By going through all this hoopla, you get automatic mock prepration and verification, just as with the automatically injected mock objects.
  • After the execution of each test method, the runner will automatically call verify() on each object variable/property marked with the [Mock] metadata. If you’d like to disable verify() from being called on all mocks for a test method, simply add the attribute “verify”, with a value of false, to your [Test] metadata (e.g. – [Test(verify="false")]). This can be helpful if you want the runner to inject the mockery and all of your mocks, but you would like to specify which mocks are verified for the test.
  • Currently this runner requires FlexUnit 4 Beta 2 and a custom build of mock-as3 to work as stated. You can find SWCs for each in the Adogo August project linked above.

What’s important to note, is that this runner is more restrictive than using the mock-as3 framework directly, so it may not suite your needs. I based this runner off of concepts I saw in the JMock runner for JUnit 4, the @Mock annotation found in Mockito for Java, and my own testing practices. If anyone finds time to play with it and you find any gremlins, let me know. In speaking with Drew, it looks like this may make it into the next release of mock-as3 along with a couple of other cool features, so I hope people find it helpful.

UPDATE: Drew has been kind enough to deploy this FU4 test runner to the mock-as3 SVN repository under the class name com.anywebcam.mock.runner.MockRunner. Please use this copy for future reference. Please also note this version will only work with FlexUnit4 Beta2 and earlier. FlexUnit4 RC1 has changed the implementation for test runners and this code will need to be updated.