I have 10 different test cases .I want to create different objects of SwfEdit, SwfButton etc just once say in function and then use those in different actions in QTP.
I tried creating a function and linked it to a test case,however it did not work.
So I am not sure what could be correct way to link all these objects across all the test cases.
If you insist on creating your objects in code instead of using the object repository, you'll need to store those objects in some type of global variable. A basic example might be for a function library:
' Declare your global variable to hold the object
Public MyObject
' Create your object from a function
Public Sub InitializeGlobalObject()
' Use Descriptive Programing to create your object
Set MyObject = Window("title:=something").Button("index:=0")
End Sub
This will allow you to create the object once and then refer to it by the variable
' Click the button
MyObject.Click
You may run into issues caching an object like this because it will tend to hold on to the last screen object that it matches, whereas the object repository will refresh the screen object each time you call it. You may need to call the 'Refresh' method on your object before you use it for the first time after it is displayed on the screen.
You should use object repository to add objects first if you are not intending to use descriptive language.
You should spy on each object and then add it.
Related
I have a custom method in an ABAP class.
I used the 'Where used' tool to show where the class is called from but, as it turns out, it's called from somewhere else I didn't expect.
So what's the best way of showing a complete list of everything that calls the method?
Due to the wonders of object-oriented programming, an instance of a class can hide behind a reference to one of its base classes or interfaces it implements. For example:
DATA foo TYPE REF TO z_my_interface.
CREATE OBJECT foo TYPE z_my_class.
" lots of more code
foo->bar( ).
You can not find this reference to z_my_class->foo with its "Where Used" list, because at that code location foo could also be a reference to an instance of any other class which implements z_my_interface. But you might be able to find this if you don't just look at the where-used list of the method but at the where-used list of the whole class or the interface / base class which declares the method.
And then there are evil dynamic programming tricks like this which determine methods and classes at runtime:
DATA foo TYPE REF TO object.
CONSTANTS: classname TYPE string VALUE 'Z_MY_CLASS',
methodname TYPE string VALUE 'BAR'.
CREATE OBJECT foo TYPE (classname).
CALL METHOD foo->(methodname).
There is no chance to find this with the where-used tool. But if the class- and/or method name does actually appear in the code (it might not, for example if they are read from a customizing table) then you can use the report RS_ABAP_SOURCE_SCAN. This handy little tool allows you to select a set of ABAP programs and search for strings (and even regular expressions) within their sourcecodes.
However, if you know the method gets called when you do something specific as a user and just want to know where, then it can be easier to just set a debugger breakpoint in the method, run into it and check the call stack.
Sorted using the code_scanner transaction.
I have defined a class like this:
Class Foo
Public SomePublicProperty
Public Function init(p_somePublicProperty)
set init = Me
SomePublicProperty= p_somePublicProperty
End Function
End Class
And then consumed that in my global.asa Application_OnStart lke this:
Dim fooInstance
Set fooInstance = New Foo.init("Some data")
fooArray = Array(fooInstance)
Application("fooArray") = fooArray
Which works fine but when i get the value back out of the application store on another page i can't get at the property...
fooArray = Application("fooArray")
fooArray(0).SomePublicProperty 'This line returns an error - Object doesn't support this property or method
I have tried putting the class definition into the second page, but it doesn't help.
What have I missed?
I have just found this question. Am I right in assuming the same rule re serialization applies equally to the Application object? and so i shouldn't try and do this?
Unfortunately you can't do this, here is a the best explanation I could find as to why;
From Can I store VBScript class objects in a Session variable?
This is because VBS classes are NOT true classes. They are really just in-memory collections of info, and there is no way to guarantee (for example) that an instance that is stored in one page will even come close to matching the class definition in another page.
This is not the same as using Server.CreateObject() COM objects which can be stored and retrieved from both the Application and Session objects.
You have a couple of options;
Serialise the object yourself, in a structured string then use this to de-serialise the object when needed.
Create a COM wrapper for your VBScript class and stop using Class statement altogether. As COM objects can be stored in Application and Session objects this should work as long as the COM class is single threaded.
Convert your class into an Array and use this instead.
Useful Links
Application Object (IIS)
Setting the Scope of COM Objects in ASP Pages - Giving an Object Application Scope
Sandy Metz says (POODR book, page 26):
Because it is possible to wrap every instance variable in a method and to therefore treat any variable as if it's just another object, the distinction between data and a regular object begins to disappear.
I am not sure if I understand what she is explaining. When we define the accessors, we are wrapping the instance variables (data) on a method but methods are not objects. So what does she mean when she says that we can treat variables as if they're just another object?
The primary difference between data and objects is behaviour. Objects can modify their internal state without changing their interfaces, while data are static structures.
When we wrap data access within a method, we get the same benefits of an object - the interface remains static to consumers even if the underlying data structure needs to change.
For an unknown reason, VB6 doesn't interact the same way with UserControl than other object.
I have a class that require to hold a graphical interface, a user control and need to be set to be later used from the get method. I have try many thing like using the special class VBControlExtender but without any success.
Here is what I have so far:
Class that hold variables and the user control:
'...
Private WithEvents m_uGUI As VBControlExtender
Public Property Get GUI() As VBControlExtender
Set GUI = m_uGUI
End Property
Public Property Set GUI(ByVal uValue As VBControlExtender)
Set m_uGUI = uValue
End Property
'...
Call of the class that cannot compile:
Set myObject.GUI = new ucMyUserControl
Any idea?
From the help on this error (it mentions ListBox and Form, but the same applies to UserControls):
The New keyword can only be applied to
a creatable object... You tried to
instantiate an Automation object, but
it was not a creatable object. For
example, you tried to create a new
instance of a list box by specifying
ListBox in a statement like the
following: [sample code snipped]
ListBox and Form are class names, not
specific object names. You can use
them to specify that a variable will
be a reference to a certain object
type... But you can't use them to
instantiate the objects themselves in
a Set statement. You must specify a
specific object, rather than the
generic class name, in the Set
statement:
What you want to do is make an array of your UserControls and load new ones as you need them. Set the Index property of your UserControl to 0 to make it an array and then use the Load statement to create new instances:
Load ucMyUserControl(1)
Set myObject.GUI = ucMyUserControl(1)
When you need more just specify a new upper bound:
Load ucMyUserControl(2)
Load ucMyUserControl(3)
...
When you're done with them, unload them:
Unload ucMyUserControl(3)
Unload ucMyUserControl(2)
...
I believe VBControlExtender can only be used with dynamically added controls (i.e. Controls.Add) not intrinsic controls. Why can't you use ucMyUserControl as the type instead?
I've written a very simple GUI in MATLAB that will convert temperatures. It is meant to serve as a tutorial for a class of students. A strange thing has happened though. As with any MVC design pattern, there is a model object, a view object and a controller function. In order to set the output field of the GUI (the converted temperature), you can run this line in the controller function itself:
set(views.outputTextField,'string',num2str(round(model.outTemp)));
where views.outputTextField is a GUI text field to display the converted temperature and model.outTemp is the converted temperature. Pretty straightforward. The views object has references to all the GUI uicontrols and this updates the field with the newly converted temperature in the model object.
However, I would rather have view functions in the view object, so I attempted to create a line like this:
views.updateOutputField = #()set(views.outputTextField,'string',...
num2str(round(model.outTemp)));
Same line as before, just that now it is an anonymous function in the view object. This way I could call the function from the controllers as simply views.updateOutputField(); and keep the view logic out of the controller logic. But this method won't work! (It will work with the get() function.)
Instead I have to do the following:
views.updateOutputField = #updateOutputField
function updateOutputField()
set(views.outputTextField,'string',num2str(round(model.outTemp)));
end
By separating out the function (redundantly) instead of just using an anonymous function, it works again. What!? This makes no sense to me. The view and model objects are global and the anonymous function works with get(). Does anyone have a clue what's going on here?
Both approaches are not equivalent. Values in the body of anonymous function (aka lambda) are being frozen, see example below:
>> ii = 2;
>> val = #() ii+2;
>> val()
ans =
4
>> ii=5;
>> val()
ans =
4
You can do following to make it work:
views.updateOutputField = #(outTemp) ...
If you want to know how MATLAB captures the workspace context, use function FUNCTIONS on anonymous function.
Your example is a little bit more complicated because your view and model exist in the nested workspace but the essence is the same.
As side note: kudos for teaching also an important design pattern (MVC) in Matlab class!
Mikhail has the right answer. I'll elaborate a bit...
From the MATLAB documentation for anonymous functions:
Anonymous functions commonly include
two types of variables:
Variables specified in the argument
list. These often vary with each
function call.
Variables specified in the body of the
expression. MATLAB captures these
variables and holds them constant
throughout the lifetime of the
function handle.
When you make a call to SET inside your anonymous function, you access fields of your two structure variables views and model. These values are held fixed at what they were when the anonymous function was created. That doesn't matter for the graphics handles stored in views, since these never change (unless you are deleting and recreating graphics objects). This is why calling GET in your anonymous function works fine, since it only uses the unchanged graphics handles in views. However, the values in model change, so you would want to pass them in to the anonymous function as an argument. For example:
views.updateOutputField = #(model) set(views.outputTextField,'String',...
num2str(round(model.outTemp)));
When you instead create your updateOutputField function, you are creating a nested function. Nested functions have access to the variables that exist in the outer function within which they are nested, which is why you don't have to pass views and model as arguments. When these variables change in the outer function, that change is visible in the nested function as well (unlike anonymous functions).