Skip to content
Browse files

add support to inject the generated proxy class into tests.

for example:

    [Mock]
    public var example:Example;

    [ProxyClass(of="example")]
    public var exampleProxyClass:Class;
  • Loading branch information...
1 parent a34fbbe commit 6ae3801ada8bffddc4933597d463a2293bdbfdd3 @drewbourne committed
View
2 build.xml
@@ -46,7 +46,7 @@
<include name="flexunit*.swc" />
<include name="hamcrest*.swc" />
</external-library-path>
- <keep-as3-metadata name="Mock" />
+ <keep-as3-metadata name="Mock,ProxyClass" />
<compiler.define name="CONFIG::useFlexClasses" value="@{useFlexClasses}" />
</compc>
</sequential>
View
2 mockolate-unit-test/src/mockolate/MockolateSuite.as
@@ -19,6 +19,7 @@ package mockolate
import mockolate.runner.MockolateRuleExample;
import mockolate.runner.MockolateRunnerExample;
import mockolate.runner.statements.IdentifyMockClassesTest;
+ import mockolate.runner.statements.InjectMockInstancesTest;
import mockolate.runner.statements.VerifyMockInstancesTest;
[Suite]
@@ -87,6 +88,7 @@ package mockolate
public var runnerExample:MockolateRunnerExample;
public var ruleExample:MockolateRuleExample;
public var identifyMockClasses:IdentifyMockClassesTest;
+ public var injectMockInstances:InjectMockInstancesTest;
public var verifyMockInstances:VerifyMockInstancesTest;
//
View
20 mockolate-unit-test/src/mockolate/runner/statements/IdentifyMockClassesTest.as
@@ -6,6 +6,7 @@ package mockolate.runner.statements
import mockolate.arg;
import mockolate.expect;
+ import mockolate.ingredients.InstanceRecipe;
import mockolate.ingredients.Mockolatier;
import mockolate.ingredients.mockolate_ingredient;
import mockolate.nice;
@@ -97,6 +98,25 @@ package mockolate.runner.statements
}
[Test]
+ public function evaluate_should_populate_instanceRecipes_proxyClassFieldName():void
+ {
+ withMockolatier();
+
+ var runnerData:MockolateRunnerData = new MockolateRunnerData();
+ runnerData.test = new TestExampleWithProxyClassInjection();
+ runnerData.mockolatier = mockolatier;
+
+ var token:AsyncTestToken = new AsyncTestToken();
+ var statement:IdentifyMockClasses = new IdentifyMockClasses(runnerData);
+
+ statement.evaluate(token);
+
+ var instanceRecipe:InstanceRecipe = runnerData.instanceRecipes.toArray()[0];
+
+ assertThat('identified proxyClasssFieldName', instanceRecipe.proxyClassFieldName, equalTo('exampleProxy'));
+ }
+
+ [Test]
public function evalue_should_throw_error_for_unsupported_metadata_attributes():void
{
var runnerData:MockolateRunnerData = new MockolateRunnerData();
View
29 mockolate-unit-test/src/mockolate/runner/statements/InjectMockInstancesTest.as
@@ -0,0 +1,29 @@
+package mockolate.runner.statements
+{
+ import mockolate.runner.MockolateRule;
+ import mockolate.sample.ExampleClass;
+
+ import org.hamcrest.assertThat;
+ import org.hamcrest.core.not;
+ import org.hamcrest.object.nullValue;
+ import org.hamcrest.object.instanceOf;
+
+ public class InjectMockInstancesTest
+ {
+ [Rule]
+ public var mocks:MockolateRule = new MockolateRule();
+
+ [Mock]
+ public var example:ExampleClass;
+
+ [ProxyClass(of="example")]
+ public var exampleProxy:Class;
+
+ [Test]
+ public function exampleProxy_should_be_injected_with_generated_proxy_class():void
+ {
+ assertThat("exampleProxy should be injected", exampleProxy, not(nullValue));
+ assertThat("example should be an instance of exampleProxy Class", example, instanceOf(exampleProxy));
+ }
+ }
+}
View
2 mockolate-unit-test/src/mockolate/runner/statements/TestExample.as
@@ -37,7 +37,7 @@ package mockolate.runner.statements
[Mock]
public var dispatcher:IEventDispatcher;
-
+
public var nonMockField:Boolean;
[Test]
View
18 mockolate-unit-test/src/mockolate/runner/statements/TestExampleWithProxyClassInjection.as
@@ -0,0 +1,18 @@
+package mockolate.runner.statements
+{
+ import mockolate.sample.ExampleClass;
+
+ public class TestExampleWithProxyClassInjection
+ {
+ [Mock]
+ public var example:ExampleClass;
+
+ [ProxyClass(of="example")]
+ public var exampleProxy:Class;
+
+ [Test]
+ public function unused():void
+ {
+ }
+ }
+}
View
1 mockolate/src/mockolate/ingredients/InstanceRecipe.as
@@ -10,6 +10,7 @@ package mockolate.ingredients
public var mockType:MockType;
public var name:String;
public var inject:Boolean = true;
+ public var proxyClassFieldName:String;
public var instance:*;
public var mockolate:Mockolate;
View
38 mockolate/src/mockolate/runner/statements/IdentifyMockClasses.as
@@ -69,6 +69,7 @@ package mockolate.runner.statements
}
import asx.array.compact;
+import asx.array.detect;
import asx.array.filter;
import asx.array.map;
import asx.array.pluck;
@@ -106,6 +107,9 @@ internal class MockolateRecipeIdentifier
private const SUPPORTED_ATTRIBUTES:Array = [ ARGUMENTS_ATTRIBUTE, NAMESPACES_ATTRIBUTE, INJECT_ATTRIBUTE, MOCK_TYPE_ATTRIBUTE ];
private const TRUE:String = "true";
private const FALSE:String = "false";
+
+ private const PROXYCLASS_METADATA:String = "ProxyClass";
+ private const OF_ATTRIBUTE:String = "of";
private var _mockolatier:Mockolatier;
@@ -169,6 +173,7 @@ internal class MockolateRecipeIdentifier
public function identifyInstanceRecipes(test:*, fromKlass:Klass, withClassRecipes:ClassRecipes, intoInstanceRecipes:InstanceRecipes):void
{
var mockFields:Array = filter(fromKlass.fields, isMockField);
+ var proxyClassFields:Array = filter(fromKlass.fields, isProxyClassField);
for each (var field:Field in mockFields)
{
@@ -176,6 +181,7 @@ internal class MockolateRecipeIdentifier
var namespaces:Array = parseNamespacesToProxy(test, fromKlass, field, metadata);
var classRecipe:ClassRecipe = withClassRecipes.getRecipeFor(field.type, namespaces);
var injectable:Boolean = parseInject(field, metadata);
+ var proxyClassField:Field = detect(proxyClassFields, isProxyClassFieldForMockField(field)) as Field;
if (injectable)
{
@@ -185,11 +191,38 @@ internal class MockolateRecipeIdentifier
.withMockType(parseMockType(field, metadata))
.withName(field.name)
.build();
+
+ if (proxyClassField)
+ {
+ instanceRecipe.proxyClassFieldName = proxyClassField.name;
+ }
intoInstanceRecipes.add(instanceRecipe);
}
}
}
+
+ private function isMockField(field:Field):Boolean
+ {
+ return field.hasMetaData(MOCK_METADATA);
+ }
+
+ private function isProxyClassField(field:Field):Boolean
+ {
+ return field.hasMetaData(PROXYCLASS_METADATA);
+ }
+
+ private function isProxyClassFieldForMockField(mockField:Field):Function
+ {
+ return function(proxyField:Field):Boolean
+ {
+ var metadata:MetaDataAnnotation = proxyField.getMetaData(PROXYCLASS_METADATA);
+ var of:MetaDataArgument = metadata.getArgument(OF_ATTRIBUTE);
+ var ofValue:String = (of ? of.value : "");
+
+ return mockField.name == ofValue;
+ }
+ }
private function parseConstructorArgs(test:*, klass:Klass, field:Field, metadata:MetaDataAnnotation):Function
{
@@ -217,11 +250,6 @@ internal class MockolateRecipeIdentifier
return null;
}
- private function isMockField(field:Field):Boolean
- {
- return field.hasMetaData(MOCK_METADATA);
- }
-
private function parseNamespacesToProxy(test:*, klass:Klass, field:Field, metadata:MetaDataAnnotation):Array
{
var attribute:MetaDataArgument = metadata.getArgument(NAMESPACES_ATTRIBUTE);
View
5 mockolate/src/mockolate/runner/statements/InjectMockInstances.as
@@ -46,6 +46,11 @@ package mockolate.runner.statements
forEach(data.instanceRecipes.toArray(), function(instanceRecipe:InstanceRecipe):void {
data.test[instanceRecipe.name] = instanceRecipe.instance;
+
+ if (instanceRecipe.proxyClassFieldName)
+ {
+ data.test[instanceRecipe.proxyClassFieldName] = instanceRecipe.classRecipe.proxyClass;
+ }
});
parentToken.sendResult();

2 comments on commit 6ae3801

@jbarrus

How is this different from obtaining the class from a proxy instance?

var klass:Class = Class(getDefinitionByName(getQualifiedClassName(example)))

or

var klass:Class = Object(example) .constructor
@drewbourne
Owner

The difference is it doesn't require an instance of the proxy class to have been instantiated from which to derive the class. Which is important when you want to inject different constructor arguments or to augment the constructor process.

Being able to augment the constructor process will come as a feature once I complete the integration of as3-commons-bytecode. Using as3-commons-bytecode as the proxy generation backend exposes a significant number of hooks to customize the proxy generation and instantiation processes.

Please sign in to comment.
Something went wrong with that request. Please try again.