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.
Related
I am using serilog with the sinks File and RollingFile in a crosscutting dll that delivers a logging service. I am configuring with the Appsettings nuget, therefore I have no static dependency to the mentioned sinks. However I do need them at runtime and they are not copied to the bin folder of the application, only to the bin folder of the dll. That means I get a Runtime Exception because the sink-dlls are not there. Is there a way to fix that? My workaround is creating a Variable of type RollingFileSink that I never use. But it is kind of ugly. UPDATE: that solution does not work in Release btw.
I had this issue before with Serilog, and the way I resolved it was to create a static reference to a type inside the assemblies I needed, via an assembly-level attribute that I declare inside the AssemblyInfo.cs of my main project.
Something like this:
[assembly: ImplicitDependency(typeof(Serilog.Sinks.RollingFile.RollingFileSink))]
[assembly: ImplicitDependency(typeof(Serilog.Sinks.File.PeriodicFlushToDiskSink))]
// etc...
And this is the attribute I created inside my project...
/// <summary>
/// Indicates that the marked assembly depends on the type that is specified in the constructor.
/// Typically used to force a compile-time dependency to the assembly that contains the type.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class ImplicitDependencyAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ImplicitDependencyAttribute"/> class.
/// </summary>
/// <param name="dependencyType">A type from the assembly that is used dynamically.</param>
public ImplicitDependencyAttribute(Type dependencyType)
{
DependencyType = dependencyType;
}
/// <summary>
/// Gets the dependent type reference.
/// </summary>
/// <value>The dependent type reference.</value>
public Type DependencyType { get; private set; }
}
It seems like StdSchedulerFactory returns a singleton with the name defined in config:
<add key="quartz.scheduler.instanceName" value="MyQuartzScheduler" />
As quartz config section consists of key value pairs it looks like using factory for instantiating scheduler limits the number of available schedulers to one.
AFIAK, you can create as many schedulers as you like within any application, but you cannot use default quartz config approach for this, as it expect only one collection of scheduler properties (look into StdSchedulerFactory implementation and this blog if interesting):
By default, In Quartz.Net, the StdSchedulerFactory is responsible for configuring the scheduler. When the Quartz.Net scheduler is started, the factory will try to automatically configure a scheduler by looking for configuration information in different places:
the hosting application’s configuration file
a file specified in an environment variable
the quartz.config file
the embedded configuration file
SO what you can do is not to use automatic scheduler configuration, but
by himself create a separate collections of properties and pass them to scheduler creation constructors:
public StdSchedulerFactory(NameValueCollection props);
using code approach:
NameValueCollection scheduler1Properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "SingleThreadScheduler";
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "1";
...
var factory = new StdSchedulerFactory(scheduler1Properties);
or you can create separate quartz configs and directly use quartz PropertiesParser class to read
/// <summary>
/// Reads the properties from file system.
/// </summary>
/// <param name="fileName">The file name to read resources from.</param>
/// <returns></returns>
public static PropertiesParser ReadFromFileResource(string fileName)
and get collection:
/// <summary>
/// Gets the underlying properties.
/// </summary>
/// <value>The underlying properties.</value>
public virtual NameValueCollection UnderlyingProperties
{
get { return props; }
}
// PropertiesParser class is directly used in default config reading implementation.
I wish to have the sub-classes of a super-class "registered" by an arbitrary name - whenever I declare a sub-class I wish to also have it entered into the super-class.sub Map.
Is there any way to accomplish this outside of main()?
// base class
class Mineral{
final String formula;
static Map<String,Mineral> sub = {}
Mineral( this.formula );
}
// sub class - declare and register
class Mica extends Mineral{
Mica( String formula ) : super( formula );
}
Mineral.sub['mica'] = Mica; // oops!
when I run this, I get
Error: line 10 pos 1: unexpected token 'Mineral' Mineral.sub['mica'] = Mica;
assuming that executable code is not allowed outside main().
cannot put within the super-class since other sub-classes may declared later, outside the library.
Dart has no way to run code as part of a library being loaded.
Executable code can only be put inside methods, or in field initializers, and static field initializers are lazy so they won't execute any code until you try to read them.
This is done to ensure quick startup - a Dart program doesn't have to execute any code before starting the main library's "main" method.
So, no, there is no way to initialize something that isn't constant before main is called.
Either
Mineral.sub['mica'] = new Mica();
or
static Map<String,Type> sub = {};
When you assign Mica you assign the Type Mica. new Mica() is an instance of Mica that is of the kind Mineral and can be assigned to the map you declared.
edit
Maybe you want to initialize the sub map:
static Map<String,Mineral> sub = {'mica': new Mica()};
hint: the semicolon is missing in this line in your question.
Spring documentation on http://springframework.net/docs/1.3.1/reference/html/objects.html says:
"In addition to object definitions which contain information on how to
create a specific object, the IApplicationContext implementations also
permit the registration of existing objects that are created outside
the container, by users. This is done by accessing the
ApplicationContext's IObjectFactory via the property ObjectFactory
which returns the IObjectFactory implementation
DefaultListableObjectFactory. DefaultListableObjectFactory supports
registration through the methods RegisterSingleton(..) and
RegisterObjectDefinition(..)."
I'm trying to access the ObjectFactory object after doing the following:
var context = ContextRegistry.GetContext();
But there is no ObjectFactory property. I'm using Spring.Net v1.3.1.20711 and have Spring.Core referenced in my project.
What am I missing?
The ObjectFactory property is not exposed by the IApplicationContext interface, but is part of the IConfigurableListableObjectFactory interface.
Your context variable will be of inferred type IApplicationContext, because of the return type of ContextRegistry.GetContext(), so in VS it will appear that the ObjectFactory property is not available. However, if you take a closer look, you will see that it is an XmlApplicationContext that has the ObjectFactory property, because it implements IConfigurableListableObjectFactory. As Sebastian points out in his answer, most (if not all) application contexts implement this interface.
E.g.:
var ctx = new XmlApplicationContext("objects.xml");
ctx.ObjectFactory.RegisterSingleton("MyObject2", new MyClass() { Name = "MyObject2"});
var o2 = (MyClass)ctx.GetObject("MyObject2");
Assert.AreEqual("MyObject2", o2.Name);
Just to add to Marjin's answer; here is an extension method to get the Factory which I use.
/// <summary>
/// Gets the ObjectFactory from the Spring context.
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public static IConfigurableListableObjectFactory Factory(this IApplicationContext context)
{
return ((IConfigurableApplicationContext)context).ObjectFactory;
}
Is there a way to use Property Injection in Ninject 2 without using the [Inject] attribute? This creates a dependency to Ninject in the class that will be wired using it and I prefer to avoid having unneeded dependencies to my IoC container, that's why I end up using Constructor Injection more often.
I guess the same applies to Method Injection
I followed Ruben's tip and posted a small blog post on how to achieve this, but here's the quick answer:
Create a custom attribute:
public class InjectHereAttribute : Attribute
{
}
The target class will now look like this:
public class Samurai
{
[InjectHere]
public IWeapon Context { get; set; }
}
Now Ninject must be configured to use the custom attribute, this can be done by creating an implementation of IInjectionHeuristic that recognizes the custom attribute:
public class CustomInjectionHeuristic : NinjectComponent, IInjectionHeuristic, INinjectComponent, IDisposable
{
public new bool ShouldInject(MemberInfo member)
{
return member.IsDefined(
typeof(InjectHereAttribute),
true);
}
}
And finally add this behavior to the Ninject Kernel using the Components collection, it will run along the existing components, namely the default implementation of IInjectionHeuristic, which means either the default or the custom attribute can be used.
// Add custom inject heuristic
kernel.Components.Add<IInjectionHeuristic, CustomInjectionHeuristic>();
You can pass in another [attribute] type to the Kernel upon creation which can be used instead of InjectAttribute, but you'll still have to reference something centrally OOTB.
There was a similar question very recently about doing PI without attributes - there's no OOTB (as in directly on the fluent configuration interface) to put in a custom scanner but the extensibility points (you add a component that implements a Ninject interface as you build your Kernel that dictates how that aspect is to be work if looking for a given attribute isnt't what you want) are in there to determine where to inject based on Convention over Configuration - there's nothing stopping you amending the scanning to be based on just an attribute name (so it doesnt necessarily have to live in a central location).
Note that, in general, constructor injection is good for lots of reasons anyway, including this one, and keeping you code container agnostic is important (even if you're currently happy with one!)
I was able to accomplish this using a Heuristic class:
public sealed class MyInjectionHeuristic : NinjectComponent, IInjectionHeuristic
{
private static readonly IList<Type>
_propertyInjectible =
new List<Type>
{
typeof(IMyService),
};
/// <summary>
/// Returns a value indicating whether the specified member should be injected.
/// </summary>
/// <param name="member">The member in question.</param>
/// <returns><c>True</c> if the member should be injected; otherwise <c>false</c>.</returns>
public bool ShouldInject(MemberInfo member)
{
var info = member as PropertyInfo;
if( member == null || info == null )
return false;
if (info.CanWrite)
return _propertyInjectible.Contains(info.PropertyType);
if( this.Settings == null )
return false;
var propList = member.GetCustomAttributes(this.Settings.InjectAttribute, true);
return propList.Length > 0;
}
}
When creating your kernel:
var heuristics = _kernel.Components.Get<ISelector>().InjectionHeuristics;
heuristics.Add(new MyInjectionHeuristic());
Simple add additional types to the IList when you want to inject other types via properties.