Access fields of a TestNG test class from a TestListenerAdapter - reflection

Background
I have the following situation:
My test-classes implement org.testng.ITest
They all have a Helper containing info on the current test environment (e.g. device-under-test)
For example:
com.company.appundertest.Helper h;
public class TestClass implements org.testng.ITest {
private String testName;
//Helper is initialized externally in Factory + DataProvider
//and passed to Constructor.
public TestClass(com.company.appundertest.Helper hh) {
this.h = hh;
//constructor sets the test-name dynamically
//to distinguish multiple parallel test runs.
this.testName = "some dynamic test name";
}
#Override
public String getTestName() {
return this.testName;
}
#Test
public void failingTest() {
//test that fails...
}
}
These test-classes are executed in parallel using Factory and parallel data-provider.
Upon Test Failure, I need to access variables within the Helper instance of the failing test-class. These will be used to identify the environment at the point of failure (e.g. take screenshot on failing device).
This problem essentially boils down to:
How would I access fields within the TestNG test-class?
References
Access to private inherited fields via reflection in Java

Here's an example method. You can insert this in a Test Listener class (which extends TestListenerAdapter)
public class CustomTestNGListener extends TestListenerAdapter{
//accepts test class as parameter.
//use ITestResult#getInstance()
private void getCurrentTestHelper(Object testClass) {
Class<?> c = testClass.getClass();
try {
//get the field "h" declared in the test-class.
//getDeclaredField() works for protected members.
Field hField = c.getDeclaredField("h");
//get the name and class of the field h.
//(this is just for fun)
String name = hField.getName();
Object thisHelperInstance = hField.get(testClass);
System.out.print(name + ":" + thisHelperInstance.toString() + "\n");
//get fields inside this Helper as follows:
Field innerField = thisHelperInstance.getClass().getDeclaredField("someInnerField");
//get the value of the field corresponding to the above Helper instance.
System.out.println(innerField.get(thisHelperInstance).toString());
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Call this as follows:
#Override
public void onTestFailure(ITestResult tr) {
getCurrentTestHelper(tr.getInstance());
}

The #Vish 's solution is good, but you can avoid reflection with:
interface TestWithHelper {
Helper getHelper();
}
where your TestClass will implement it.
Then:
private void getCurrentTestHelper(Object testClass) {
if (testClass instanceof TestWithHelper) {
Helper helper = ((TestWithHelper) testClass).getHelper();
...
}
}

Related

BizTalk Custom Pipeline Component doesn't load overridden properties

I have a custom BizTalk 2013 R2 pipeline component that has several design-time properties defined. For some reason, BizTalk will load the design-time property values set in the VS pipeline designer but it ignores run-time values set in the BizTalk Admin Console. My component implements IPersistPropertyBag and I have verified that it is not throwing any exceptions.
While debugging the pipeline (attached to Isolated Host Instance), I noticed that BizTalk is only calling the Load method when the pipeline is instantiated. This only loads the VS designer values and BizTalk is supposed to then call the Load method again before calling Execute. Unfortunately, this is not happening.
[Edit] I did some more debugging and figured out that this only seems to be happening on the send pipeline for a two-way receive port. The receive pipeline loads both the design-time and run-time properties as expected.
Here is a sample of my code:
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Encoder)]
[System.Runtime.InteropServices.Guid(COMPONENT_GUID)]
public class RhapsodyMessageEncoder : BasePipelineComponent, IBaseComponent, IComponentUI,
IPersistPropertyBag, Microsoft.BizTalk.Component.Interop.IComponent
{
...
public void Load(IPropertyBag propertyBag, int errorLog)
{
try
{
this.Enabled = Convert.ToBoolean(this.ReadPropertyBag(propertyBag, "Enabled"));
this.UsernameSSOKey = this.ReadPropertyBag(propertyBag, "UsernameSSOKey") as string;
this.PasswordSsoKey = this.ReadPropertyBag(propertyBag, "PasswordSsoKey") as string;
this.AffiliateAppName = this.ReadPropertyBag(propertyBag, "AffiliateAppName") as string;
}
catch (Exception e) { this.WriteErrorLog(e); }
}
public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
{
try
{
this.WritePropertyBag(propertyBag, "Enabled", this.Enabled);
this.WritePropertyBag(propertyBag, "UsernameSSOKey", this.UsernameSSOKey);
this.WritePropertyBag(propertyBag, "PasswordSsoKey", this.PasswordSsoKey);
this.WritePropertyBag(propertyBag, "AffiliateAppName", this.AffiliateAppName);
}
catch (Exception e) { this.WriteErrorLog(e); }
}
...
}
Read / Write Property bag helper methods:
protected virtual object ReadPropertyBag(IPropertyBag pb, string propName)
{
PropertyInfo pInfo = this.GetType().GetProperty(propName);
object currentValue = null;
object val = null;
if (pInfo != null)
currentValue = pInfo.GetValue(this, null);
try
{
pb.Read(propName, out val, 0);
}
catch (System.ArgumentException e)
{
System.Diagnostics.Trace.WriteLine(
"Argument Exception encountered: " + e.Message,
this.Name
);
}
catch (System.Exception e)
{
throw new System.ApplicationException("Can't read design time Properties", e);
}
return val ?? currentValue;
}
protected virtual void WritePropertyBag(IPropertyBag pb, string propName, object val)
{
try
{
object obj = val;
pb.Write(propName, ref obj);
}
catch (System.Exception e)
{
throw new System.ApplicationException("Can't write design time properties", e);
}
}

Get all registered listeners to an ObservableValue

How to get all listeners to an observable value? I could extend the class and override addListener and removeListener methods to store them in a set. But the set should already be stored somehow inside observable value. How could I get that set?
I find a way around it, you can't get direct access to the Listeners list but if you use a debugger(I use IntelliJ) you can see it if you look inside your ObservableProprty like this:(I hope this is clear enough)
another way:(You're a smart guy, you'll know how to fit into your case)
//SimpleFloatProperty we want to find its Listeners
FloatPropertyBase f=ampPS.currentProperty();
Object value;
ChangeListener[] list;
ChangeListener changeListener=null;
Field field = null;
try {
field = FloatPropertyBase.class.getDeclaredField("helper");
field.setAccessible(true);
value = field.get(f);
try {
field = value.getClass().getDeclaredField("listener");
field.setAccessible(true);
changeListener =(WeakChangeListener)field.get(value);
}catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
field = value.getClass().getDeclaredField("changeListeners");
field.setAccessible(true);
list =(ChangeListener[])field.get(value);
}catch (NoSuchFieldException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
the result:
(Notice the difference between 1 listener or more than 1)
I I'm adding Example for several types of values
public static ChangeListener[] getChangeListeners(ObservableValue observableValue){
Object value;
ChangeListener[] list=null;
ChangeListener changeListener=null;
Field field = null;
try {
if(observableValue instanceof SimpleFloatProperty ){
field = FloatPropertyBase.class.getDeclaredField("helper");
}
else if(observableValue instanceof SimpleBooleanProperty ){
field = BooleanPropertyBase.class.getDeclaredField("helper");
}
else if(observableValue instanceof SimpleIntegerProperty ){
field = IntegerPropertyBase.class.getDeclaredField("helper");
}
field.setAccessible(true);
value = field.get(observableValue);
try {
field = value.getClass().getDeclaredField("listener");
field.setAccessible(true);
changeListener =(ChangeListener)field.get(value);
}catch (NoSuchFieldException e) {
//e.printStackTrace();
}
try {
field = value.getClass().getDeclaredField("changeListeners");
field.setAccessible(true);
list =(ChangeListener[])field.get(value);
}catch (NoSuchFieldException e) {
//e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if(list!=null){
return list;
}
else {
ChangeListener[] changeListeners = new ChangeListener[1];
changeListeners[0]=changeListener;
return changeListeners;
}
}
and I call it:
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(true);
SimpleFloatProperty simpleFloatProperty = new SimpleFloatProperty(0);
SimpleIntegerProperty simpleIntegerProperty = new SimpleIntegerProperty(1);
booleanProperty.addListener(changeListener);
simpleFloatProperty.addListener(changeListener);
simpleIntegerProperty.addListener(changeListener);
simpleIntegerProperty.addListener(changeListener);
System.out.println(getChangeListeners(booleanProperty).length);
System.out.println(getChangeListeners(simpleFloatProperty).length);
System.out.println(getChangeListeners(simpleIntegerProperty).length);
the result:
so I do get warnings, but the job is done!
The documentation for ObservableValue.removeListener states:
If the given listener has not been previously registered (i.e. it was never added) then this method call is a no-op.
This leaves a few options if reflection is to be avoided.
First, call removeListener before adding the listener, such as:
final var property = someProperty();
final var listener = getListener();
property.removeListener( listener );
property.addListener( listener );
This technique is equivalent to using a Set, provided getListener() always returns the same object reference. (This may also work if different object references of the same class override equals to return true, but you'd have to double-check.)
The downside is having to keep a reference to the listener that was added, which could require a new class, but will at least require a new instance variable.
Second, keep a map of registered listeners, something to the effect of:
final HashMap<ObservableValue<?>, Object> map = new HashMap<>();
final var property = someProperty();
final var listener = getListener();
map.computeIfAbsent( property, p -> {
property.addListener( listener );
return property;
});
Although the question is looking for the list of listeners, I suspect the intent of the question is to avoid adding duplicate listeners, which is a common scenario.

Accessing OutArgument value of Receive implementation child activity within custom WF4 activity

Using VS2012/.NET 4.5 I am creating a custom activity which implements a Receive child activity (as an implementation child). The parameters are in the example below fixed to just one: OutValue of type Guid.
I really would love to access the value of incoming parameter value in ReceiveDone, because I need to work with it and transform it before returning it from the activity. Please ignore that I am currently using a Guid, it still fails to access the value with and InvalidOperationException:
An Activity can only get the location of arguments which it owns. Activity 'TestActivity' is trying to get the location of argument 'OutValue' which is owned by activity 'Wait for
workflow start request [Internal for TestActivity]'
I have tried everything I could think of, but am stupefied. There must be a way to do this very simple thing?
public class TestActivity : NativeActivity<Guid>
{
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
var content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
// How to access the runtime value of this inside TestActivity?
{"OutValue", new OutArgument<Guid>()}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = content
};
foreach (KeyValuePair<string, OutArgument> keyValuePair in content.Parameters)
{
metadata.AddImportedChild(keyValuePair.Value.Expression);
}
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
var receive = completedInstance.Activity as Receive;
ReceiveParametersContent content = receive.Content as ReceiveParametersContent;
try
{
// This causes InvalidOperationException.
// An Activity can only get the location of arguments which it owns.
// Activity 'TestActivity' is trying to get the location of argument 'OutValue'
// which is owned by activity 'Wait for workflow start request [Internal for TestActivity]'
var parmValue = content.Parameters["OutValue"].Get(context);
}
catch (Exception)
{ }
}
private Receive startReceiver;
private const string Namespace = "http://company.namespace";
}
Use internal variables to pass values between internal activities.
Although not directly related to your code, see the example below which should give you the idea:
public sealed class CustomNativeActivity : NativeActivity<int>
{
private Variable<int> internalVar;
private Assign<int> internalAssign;
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
internalVar = new Variable<int>("intInternalVar", 10);
metadata.AddImplementationVariable(internalVar);
internalAssign = new Assign<int>
{
To = internalVar,
Value = 12345
};
metadata.AddImplementationChild(internalAssign);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(internalAssign, (activityContext, instance) =>
{
// Use internalVar value, which was seted by previous activity
var value = internalVar.Get(activityContext);
Result.Set(activityContext, value);
});
}
}
Calling the above activity:
WorkflowInvoker.Invoke<int>(new CustomNativeActivity());
Will output:
12345
Edit:
In your case your OutArgument will be the internalVar
new OutArgument<int>(internalVar);
You need to use OutArgument and them to variables. See the code example with the documentation.
I may have tried everything I thought of, but I am stubborn and refuse to give up, so I kept on thinking ;)
I here have changed my example to use a Data class as a parameter instead (it does not change anything in itself, but I needed that in my real world example).
This code below is now a working example on how to access the incoming data. The use of an implementation Variable is the key:
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
And the OutArgument:
new OutArgument<Data>(runtimeVariable)
I can then access the value with:
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
I haven't seen an example elsewhere, which does exactly this. Hope it will be of use to any one but me.
The code:
[DataContract]
public class Data
{
[DataMember]
Guid Property1 { get; set; }
[DataMember]
int Property2 { get; set; }
}
public class TestActivity : NativeActivity<Guid>
{
public ReceiveContent Content { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
{"OutValue", new OutArgument<Data> (runtimeVariable)}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = Content
};
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
}
private Receive startReceiver;
private Variable<Data> runtimeVariable;
private const string Namespace = "http://company.namespace";
}

Refer to session variable without casting it to its type everytime

I have a session variable that is a class instance. I declared it in Global.asax:
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
Session["SiteVariables"] = new SiteVariables();
}
Now I need to refer to some of the members of this variable in several places of my solution but, as far as I understand, I have to do it this way:
SiteVariables objSiteVariables = (SiteVariables)Session["SiteVariables"];
Label1.Text = objSiteVariables.permiss;
I wonder if there is a way, e.g. setting up somewhere a static variable or something, that allows me just to do:
Label1.Text = objSiteVariables.permiss;
in any place of my project.
Thank you!
You may create your own helper type/method.
public class Util
{
public static SiteVariables Variables
{
get
{
return HttpContext.Current.Session["SiteVariables"] as SiteVariables;
}
}
}
And assign value to
Label1.Text=Util.Variables.permiss;
You can create a wrapper for the session, which will allow type safe access like this:
public class SessionHandler
{
public static SessionHandler CurrentSession
{
get
{
SessionHandler session =
(SessionHandler)HttpContext.Current.Session["SessionId"];
if (session == null)
{
session = new SessionHandler();
HttpContext.Current.Session["SessionId"] = session;
}
return session;
}
}
public SiteVariables SiteVariables { get; set; }
}
You can use it like this:
// assign
SessionHandler.CurrentSession.SiteVariables = new SiteVariables();
// retrieve
SiteVariables objSiteVariables = SessionHandler.CurrentSession.SiteVariables;
This way you can add more sessions just by adding more property to the SessionHandler class.

How to use System.Action with return type?

In the BLL class, I have written:
Private List<T> GetData(string a, string b)
{
TryAction(()=>{
//Call BLL Method to retrieve the list of BO.
return BLLInstance.GetAllList(a,b);
});
}
In the BLL Base Class, I have a method:
protected void TryAction(Action action)
{
try
{
action();
}
catch(Exception e)
{
// write exception to output (Response.Write(str))
}
}
How can I use TryAction() method with generic return type?
please have a suggestion.
You need to use Func to represent a method which will return a value.
Below is an example
private List<int> GetData(string a, string b)
{
return TryAction(() =>
{
//Call BLL Method to retrieve the list of BO.
return BLLInstance.GetAllList(a,b);
});
}
protected TResult TryAction<TResult>(Func<TResult> action)
{
try
{
return action();
}
catch (Exception e)
{
throw;
// write exception to output (Response.Write(str))
}
}
Action is a delegate that has a void return type, so if you want it to return a value, you can't.
For that, you need to use a Func delegate (there are many - the last type parameter is the return type).
If you simply want to have TryAction return a generic type, make it into a generic method:
protected T TryAction<T>(Action action)
{
try
{
action();
}
catch(Exception e)
{
// write exception to output (Response.Write(str))
}
return default(T);
}
Depending on what exactly you are trying to do, you may need to use both a generic method and Func delegate:
protected T TryAction<T>(Func<T> action)
{
try
{
return action();
}
catch(Exception e)
{
// write exception to output (Response.Write(str))
}
return default(T);
}
You should consider to use Func delegate instead of Action delegate.

Resources