Is it possible to configure Ranorex to use the same user code to identify buttons in an application (instead of renaming them for each test) and also to have a set of user defined code for any new tests. I.e. a common user code base for all tests?
Yes it is possible and very handy. What you do is have a code module library that inherits from ITestModule, e.g.
public class GenericActionsLibrary : ITestModule
and then in the user code section of the recording module have the class inherit from your library.
public class TestLoginScreen : GenericActionsLibrary
In the recording module, each time you add a user code action, the drop-down list is filled with methods from both the user code module and the GenericActionsLibrary.
Your GenericActionsLibrary will need its own static reference to the repository.
Here is how I did it. I'm using Visual Basic (VB) and not C# CS in Ranorex.
In Ranorex
"Add Code Module" MainLibrary
"Add Code Module" StartBrowser
Comment out three code blocks in the code module MainLibrary:
The first is
'Implements ITestModule
The second is
''' <summary>
''' Constructs a new instance.
''' </summary>
' Public Sub New()
' ' Do not delete - a parameterless constructor is required!
' End Sub
The third location is
''' <summary>
''' Performs the playback of actions in this module.
''' </summary>
''' <remarks>You should not call this method directly, instead pass the module
''' instance to the <see cref="TestModuleRunner.Run(Of ITestModule)"/> method
''' that will in turn invoke this method.</remarks>
' Sub Run() Implements ITestModule.Run
' Mouse.DefaultMoveTime = 300
' Keyboard.DefaultKeyPressTime = 100
' Delay.SpeedFactor = 1.0
' End Sub
Add Sub(s) for the action(s) you want to call from the other code module(s)
Public Sub OpenBrowser
Host.Local.OpenBrowser("http://www.ranorex.com", "IE", "", False, False)
End Sub
In the code module, you are calling the method that's in MainLibrary. Add the Inherits statement before the Implements statement, then call the method from the MainLibrary in the ITestModule.Run code block:
Public Class StartBrowser
Inherits MainLibrary
Implements ITestModule
''' <summary>
''' Constructs a new instance.
''' </summary>
Public Sub New()
' Do not delete - a parameterless constructor is required!
End Sub
''' <summary>
''' Performs the playback of actions in this module.
''' </summary>
''' <remarks>You should not call this method directly, instead pass the module
''' instance to the <see cref="TestModuleRunner.Run(Of ITestModule)"/> method
''' that will in turn invoke this method.</remarks>
Sub StartBrowser_Run() Implements ITestModule.Run
Mouse.DefaultMoveTime = 300
Keyboard.DefaultKeyPressTime = 100
Delay.SpeedFactor = 1.0
'Call the public method from MainLibrary Class.
OpenBrowser()
End Sub
End Class
On Ranorex's Website, it shows about creating library's that comes in handy when reusing for different projects.
Related
I need to create and use global variable as optional parameter, but do not know how I can implement it.
I created the global variable in Ranorex studio:
Also this variable appeared in Data binding tag:
But I can't use this variable in the code. (ASECore package do not contains any parameters).
You can use the global Variables in Ranorex Record module or Ranorex Code module. Let me please first make an introduction of how to use them.
Create in Record module
In the Record module, click button Variables... in the top right corner and add the variables you want to use in the redord module.
Then use them in your recording:
Create in Code module
When you create a code module, it will look like this:
/// <summary>
/// Description of MyCode.
/// </summary>
[TestModule("32310FEC-5336-4F83-B448-ABC851EE5731", ModuleType.UserCode, 1)]
public class MyCode : ITestModule
{
/// <summary>
/// Constructs a new instance.
/// </summary>
public MyCode()
{
// Do not delete - a parameterless constructor is required!
}
/// <summary>
/// Performs the playback of actions in this module.
/// </summary>
/// <remarks>You should not call this method directly, instead pass the module
/// instance to the <see cref="TestModuleRunner.Run(ITestModule)"/> method
/// that will in turn invoke this method.</remarks>
void ITestModule.Run()
{
Mouse.DefaultMoveTime = 300;
Keyboard.DefaultKeyPressTime = 100;
Delay.SpeedFactor = 1.0;
}
}
Now, right click in the code and choose "Insert new module variable". Then you can set a name and default value. Press ok and it will add something like this:
string _MyVariable = "DefaultValue";
[TestVariable("de0fb4a9-32ba-4635-8f0f-4ff6db184c3f")]
public string MyVariable
{
get { return _MyVariable; }
set { _MyVariable = value; }
}
Now, you can use the variables in the run method like normal C# properties:
repo.Calculator.CalculatorResults.PressKeys(Input_1);
repo.Calculator.PlusButton.Click();
repo.Calculator.CalculatorResults.PressKeys(Input_2);
repo.Calculator.EqualButton.Click();
How to bind Variables in Suite
When you created the global parameters, it's true that you can not bind them on the suite level.
Therefore close the dialog and right click on the Record/Code module and choose "Data binding"
In the lower table you can bind your variables of the Record/Code module to the global variables. If they have the same name, you can also Auto-bind them.
When you now execute the test suite, the values of the global variables will be used in test. If you execute the Record/Code module standalone, then the default values will be used in test.
Once you have set that variable in your highest node, you can use it and assign variables to it in lower nodes. So when you make a smart folder in your test suite and go to the data binding, you will notice the global is present under the parameters. All you need to do is make a recording with a variable that will use the global variable and link it in that folder.
I have seen a very interesting thing. I did a little mvc/rest framework based on the Slim framework.
$app->put('/:id', function ($id) {
$app->halt(500, "Error") // Here this is working.
(new RestController)->editItem($id);
})->via('put');
So I wrote a RestController which extends the BaseController, and my BaseController extends the Slim framework.
class BaseController extends \Slim\Slim {
/**
* #var \app\models\AbstractModel
*/
protected $model;
public function __construct() {
$settings = require(__DIR__ .'/../configurations/slim.php');
parent::__construct($settings);
}
}
So my BaseController can uses the Slim class's methods and properties.
class RestController extends BaseController {
public function editItem($id) {
$data = $this->getRequestBody();
$result = $this->model->update($id, $data['data']);
// This is absolutely not working, but it seems my application will die in this case.
// Because I cannot see any written message (with echo or print methods...)
// This will always return with a 200 staus code and blank page!
$this->halt(404, json_encode(array('status' => "ERROR")));
}
}
But this will work fine... and I do not get it, why?
class RestController extends BaseController {
public function editItem($id) {
$data = $this->getRequestBody();
$result = $this->model->update($id, $data['data']);
// This will work.
$app = Slim::getInstance();
$app->halt(204, json_encode(array('status' => "ERROR")));
}
}
Anyone has a good ide?
You construct a new RestController in your route by doing (new RestController). Although it extends Slim/Slim in the class hierarchy, it is a new instance of it; it is not a copy of or reference to $app, the Slim application that is actually being run.
This causes issues in the first case: you say $this->halt(...) while $this is the newly constructed RestController which is a new instance of a Slim app, not the one that is currently running. Therefore the halt call has no effect on your the output of your application.
In the second case, you say $app->halt(...) where $app is Slim::getInstance(), the global instance of your Slim application, which is the actual running Slim app. Therefore the halt call has effect on the output of your application.
You can solve the issue either by using the second approach, or by instantiating your global $app variable as a RestController, and then you can do:
$app->put('/:id', function ($id) use ($app) {
$app->halt(500, "Error") // Here this is working.
$app->editItem($id);
})->via('put');
NB; you forgot to put use ($app) in the code posted to your question, I added it in my code above. Is it present in the code you are actually running? Otherwise the $app->halt() call should result in an error in any case.
My test class like this:
public class HandlerTest extends Specification {
Handler hander
EventBus eventBus=Mock()
def setup(){
handler=new Handler(eventBus)
}
def "constructor"(){
//How to verify two events do get added to eventBus?
}
}
and Constructor of Handler(it is a java class)
public Handler(EventBus eventBus)
{
eventBus.add(FetchSearchWordsEvent.TYPE, this);
eventBus.add(SetSearchBoxTextEvent.TYPE, this);
}
Question is:
how to verify that two events do get registered?
I would move the call to Handler constructor into the test itself given that it is the function under test.
Try the following:
public class HandlerTest extends Specification {
Handler hander
def mockEventBus = Mock(EventBus)
def "constructor"(){
when:
new Handler(mockEventBus)
then:
1 * mockEventBus.add(FetchSearchWordsEvent.TYPE, _ as Handler)
1 * mockEventBus.add(SetSearchBoxTextEvent.TYPE, _ as Handler)
}
}
The functionality of EventBus.add() should be tested separately.
It depends on how registerHandler is implemented, and what exactly you want to verify. If the goal is to verify that the constructor ultimately calls some methods on eventBus, you can just use regular mocking. If the goal is to verify that the constructor calls registerHandler on itself, you can use partial mocking using Spy(), as explained in the Spock reference documentation.
PS: Note that partial mocking is considered a smell. Often it's better to change the class under test to make it easier to test. For example, you could add a method that allows to query which handlers have been registered. Then you won't need mocking at all.
I have built a simple InteropForms class using the project template in VS 2010. It builds successfully and registers the library in the system. I can see it and reference it in VB6 but none of the public methods or properties I add to the class in VS2010 are visible.
What am I doing wrong?
Imports Microsoft.InteropFormTools
<InteropForm()> _
Public Class frmWebBrowserPreview
Private Sub frmWebBrowserPreview_KeyUp(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
If e.KeyCode = Windows.Forms.Keys.Escape Then Hide()
End Sub
Private Sub frmWebBrowserPreview_MouseUp(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
Hide()
End Sub
Private Sub wbrPreview_DocumentCompleted(sender As Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles wbrPreview.DocumentCompleted
wbrPreview.Visible = True
End Sub
''' <summary>
''' Navigate to the specified URL
''' </summary>
''' <param name="strURL">The URL string</param>
Public Function Navigate(strURL As String) As Boolean
wbrPreview.Navigate(strURL)
End Function
End Class
The template comes from the toolkit: VB6 InteropForm Library
It's not supported in VS2012 (yet...)...
Toolkit for VS2012
I figured it out. You have to add an InteropFormMethod attribute to the method in question and then rebuild the wrapper.
''' <summary>
''' Navigate to the specified URL
''' </summary>
''' <param name="strURL">The URL string</param>
<InteropFormMethod()> _
Public Function Navigate(strURL As String) As Boolean
wbrPreview.Navigate(strURL)
End Function
Strange issue I am having with my MVC3 project. I have followed a simple example of IOC using Unity.Mvc.
It works fine if my object and it's interface are in the web project itself (in this case IMessageService and MessageService). They clearly are working, no problems there.
But when I try to register my business service objects from an external assembly, they never get set to anything (always null). There are no errors in App-Start when they get registered, etc.
Anyone have any ideas? Desperate here....
UPDATE:
#Region "Imports"
Imports MyProject.Services
Imports MyProject.Services.Interfaces
Imports MyProject.Web.Mvc.Bootstrap
Imports MyProject.Web.Mvc.Services
Imports Microsoft.Practices.Unity
Imports Unity.Mvc3
#End Region
#Region "Assembly Meta"
' This tells the app to run the "Start" method prior to running the App_Start method in Global.asax
<Assembly: WebActivator.PreApplicationStartMethod(GetType(UnityDI), "Start")>
#End Region
Namespace MyProject.Web.Mvc.Bootstrap
''' <summary>
''' Class to setup dependency injection and register types/services.
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class UnityDI
''' <summary>
''' Method to register the Unity dependency injection component.
''' </summary>
''' <remarks>
''' This line of code below could alternatively be placed in Global.asax App_Start(), doing
''' so in this manner ensures that this gets run "PreStart".
''' </remarks>
Public Shared Sub Start()
' Set DI resolver
' NOTE: ECD - The UnityDependencyResolver below is part of the Unity.Mvc3 assembly
DependencyResolver.SetResolver(New UnityDependencyResolver(RegisterIocServices()))
End Sub
''' <summary>
''' Registers the IOC types/services.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Shared Function RegisterIocServices() As IUnityContainer
' Create Unity dependency container
Dim dependencyContainer As IUnityContainer = New UnityContainer
' Register the relevant types/services for the container here through classes or configuration
With dependencyContainer
.RegisterType(Of IFormsAuthenticationService, FormsAuthenticationService)()
.RegisterType(Of IContactService, ContactService)()
.RegisterType(Of IProductItemService, ProductItemService)()
.RegisterType(Of ICustomerProductItemService, CustomerProductItemService)()
.RegisterType(Of ISystemTableItemService, SystemTableItemService)()
.RegisterType(Of ICatalogCodeService, CatalogCodeService)()
.RegisterType(Of IOrderService, OrderService)()
' TEST: This one is in the MVC project and works, the above are an external library
.RegisterType(Of IMessageService, MessageService)()
End With
Return dependencyContainer
End Function
End Class
End Namespace
Above code is my registration process. I have also tried putting this directly in the global.asax and have the same behavior.
UPDATE 2
Figured out my issue.
In my controller, I have the following properties:
<Dependency()>
Private Property CatalogCodeService As ICatalogCodeService
<Dependency()>
Private Property ContactService As IContactService
<Dependency()>
Private Property CustomerProductItemService As ICustomerProductItemService
But accessing the services in an action method always threw an error that there was no instance of any of these objects. So I assumed it was the original code I posted or something in there in the way I was registering.
Turns out it was not my registration code, which is perfectly fine.
The issue?
The properties have to be "Public"!! Private, Protected, Friend all do not work for IOC. Once I changed those properties to "Public", everything started working perfectly fine.
I have not verified that this is the same in C#, so if anyone can add their two cents, please by all means do so.
Go figure...
UPDATE II:
The above implementation was using public properties, which follows the "Property Injection" pattern of dependency injection.
I have since switched to the more appropriate "Constructor Injection" method.
With this change, that property for my services that my controller(s) use can be private AND read only.
"Dependency Injection in .NET" by Mark Seemann, great book. I highly suggest it for anyone implementing dependency injection or those just wanting to learn more about it.