Data Reflection implementation in TestComplete
- 9 years ago
OK... I think I have something now... I'm going the script extension route. Basically, I created an extension with a single exposed method with two parameters. The first parameter is the class name, the second parameter is a pipe delimited list of data fields to represent the properties of the object. When the method is called, using Runner.CallMethod, it returns the JScript prototype object that is declared within a unit with the same name as the class name and having the properties as defined by the pipe delimited list.
The idea is that, if I need to add a new keyword to my data tables to execute a new test type, rather than adding a new case to my switch statement, I add a new code unit for the test type containing the necessary code to execute the test step. This eliminates the need for the different case statements and modularizes the framework even further. The script extension is generalized enough that you can do this for any class you want. I am passing in the properties list becauseHere's the code if you want it and I've attached the TCX file as well.
[ClassFromName.js] //This is the code unit within the extension. It's very simple in that all //it does is run the "returnClass" method for the appropriate class unit function returnClass(className, properties){ var classMethod = className + ".returnClass"; return localObject = Runner.CallMethod(classMethod, properties); } [TestUnit] //This unit declares the class and the methods on the class using JScript/JavaScript //prototypes function WriteLog(){ Log.Message(this.Field1); Log.Message(this.Field2); } function TestUnitClass(properties){ if (VarToStr(properties) != ""){ for(var i=0;i<aqString.GetListLength(properties);i+=2){ eval("this." + aqString.GetListItem(properties, i) + "=" + aqString.Quote(aqString.GetListItem(properties, i+1))) }
} this.WriteLog = WriteLog; } function returnClass(properties){ var LocalObject = new TestUnitClass(properties); return LocalObject; } [RunTests] //This is just to demonstrate how it works function TestSomething(){ var NewObject = ClassFromName.returnClass("TestUnit", "Field1|data1|Field2|data2"); NewObject.WriteLog(); }This works also if you don't pass in the property list and declare the properties elsewhere. JScript/JavaScript allows you to dynamically add properties to an object after the fact. So, the code COULD look like this.
[TestUnit] //This unit declares the class and the methods on the class using JScript/JavaScript //prototypes function WriteLog(){ Log.Message(this.Field1); Log.Message(this.Field2); } function TestUnitClass(properties){ if (VarToStr(properties) != ""){ for(var i=0;i<aqString.GetListLength(properties);i+=2){ eval("this." + aqString.GetListItem(properties, i) + "=" + aqString.Quote(aqString.GetListItem(properties, i+1))) } } this.WriteLog = WriteLog; } function returnClass(properties){ var LocalObject = new TestUnitClass(properties); return LocalObject; } [RunTests] //This is just to demonstrate how it works function TestSomething(){ var NewObject = ClassFromName.returnClass("TestUnit"); NewObject.Field1 = "Test1"; NewObject.Field2 = "Test2"; NewObject.WriteLog(); }
I'm working on implementing this in my framework right now. If you're interested in the framework and the concepts behind writing this kind of structure, register for the TestComplete 301 Academy training.