Creating reusable method with variable conditional logic - c#

I have several variations of the following code within methods that are being used for Selenium testing (waits for certain events before returning) and I would like to refactor it and make it reusable so I have the logic controlling the delay & try/catch as a generic method but be able to swap in and out conditions depending on situation.
Is there an easy way to achieve this?
Code:
for (int second = 0; second <= 10; second++)
{
try
{
// bit that needs to vary
matchedAddresses = driver.FindElements(By.ClassName("addresslookup"));
if (matchedAddresses.Count > 0)
{
break;
}
}
catch (Exception)
{
}
Thread.Sleep(1000);
}
return matchedAddresses.Count;

You want function that takes argument of something like Func<int> - method that returns number of elements (or enumerable Func<IEnumerable<sometype>>)
public int GetCountOfElementsWithWait(Func<int> test)
{
.....
var count = test();
....
}

Seems a bit too obvious, but would this work?
public int GetCountOfElementsByClassName(string className)
{
for (int second = 0; second <= 10; second++)
{
try
{
// bit that needs to vary
matchedElements = driver.FindElements(By.ClassName(className));
if (matchedElements.Count > 0)
{
break;
}
}
catch (Exception)
{
}
Thread.Sleep(1000);
}
return matchedElements.Count;
}

Related

Loop to repeat a method 3 times if condition fails

Im looking for a simple way, to repeat a method, when an element(selector) for example a button on a webpage cant be found.
My idea or my plan is, that:
If the selector can be found, the method is done
If the selector cant be found, it should repeat the "FindElement" method up to maximal 3 times
If the selector cant be found after the third try, it should give me an output message of the "NoSuchElementException e"
I tried different loops and i always end up having endless loops like in the code below.
public static void FindElement(IWebDriver webDriver, string selector)
{
int maxTries = 0;
try
{
webDriver.FindElement(By.XPath(selector));
Console.WriteLine("Element found.");
}
catch (NoSuchElementException e)
{
if (maxTries !> 3 )
{
Console.WriteLine("Element, not found. Retrying.");
maxTries++;
FindElement(webDriver, selector);
}
else
{
Console.WriteLine(e);
}
}
}
What a coincidence: Just a few days ago I wrote a short helper method to separate "retry logic" from "business logic".
private T Retry<T>(Func<T> action, int maxRetryCount, int waitMilliseconds,
Func<Exception, bool> retryCondition)
{
var retryCount = 0;
while (true)
{
try
{
// If the action was successful (no exception thrown),
// we can leave the method.
return action();
}
catch (Exception ex) when (retryCount < maxRetryCount && retryCondition(ex))
{
retryCount += 1;
Thread.Sleep(waitMilliseconds);
}
}
}
Which would be called as follows in your case:
var element = Retry(() => webDriver.FindElement(By.XPath(selector)),
2, 0,
ex => ex is NoSuchElementException);
Whenever the maximum number of retries is reached, the exception is not caught any more (the when condition fails) and can be caught by your regular exception handling logic instead.
Since you are trying to automate a web browser, you might consider passing something else than 0 as waitMilliseconds, to give the browser time to render the elements that are still missing.
Why don't you put the maxTry outside of your function?
int maxTry=3;
string errorMessage="";
for(int i=0;i<maxTry;i++)
{
try
{
FindElement(webDriver,selector)
errorMessage="";
break;
}
catch (NoSuchElementException e)
{
errorMessage=e;
}
}
if(errorMessage!="")
{
Console.WriteLine(e);
}
else
{
Console.WriteLine("Element found.");
}
For recursion, you should pass the amount of remaining iterations to the function, and decrement it for each iteration.
public static void FindElement(IWebDriver webDriver, string selector, int iterations = 3)
{
iterations--;
if (iterations < 0)
{
Console.WriteLine("Max iterations passed, exiting")
return;
}
try
{
webDriver.FindElement(By.XPath(selector));
Console.WriteLine("Element found.");
}
catch (NoSuchElementException e)
{
Console.WriteLine("Element not found. Retrying.");
FindElement(webDriver, selector, iterations);
}
}

Get n from findelement in findelements iteration

I'm searching an element inside elements list. And if an element found I return the n of iteration.
I'm wondering is there is another faster way to do that? Currently I can do that purpose this way. But it takes time to process.
var iBtnFix = 0;
var elProfiles = driver.FindElements(By.ClassName("xxx")); // list
for (var i = 0; i < elProfiles.Count; i++)
{
try
{
elProfiles[i].FindElement(By.XPath(".//button[contains(#class,'yyy')]"));
iBtnFix = i;
break;
}
catch (Exception ex)
{
}
}
Better to use if-else condition with return statement instead of try-catch block. You can create method isElementVisible() which return boolean based on visibility of element and use its response in your if condition.
For example :
if(isElementVisible("your locator")
{
return index;
}
Method for example :
public boolean isElementVisible(By by){
boolean isElement = false;
try{
isElement = driver.findElement(by).isDisplay();
}catch(NoSuchElementFoundException e){
isElement = false;
}
return isElement;
}
This is java code. You can write according in C#.

Triggers and Actions for Creature AI

Despite my creature AI working (for the most part), I feel like the way I've set it up is terribly inefficient and likely committing some programming sins. I want to rewrite it to be more clean, efficient, and easier to maintain but I'm not exactly sure where to begin.
In my creature AI, I have a list of triggers, such as OnSpawn, OnDeath, or OnCollisionEnter. Within each trigger is a list of actions such as "Cast a Spell" or "Play an Animation". When a trigger's conditions are met, its list of actions are processed to check if it's not already in our processing list, adds it, and then plays their associated actions. When the trigger's conditions are not met, the list of actions are removed from this process list, and similarly processes through some remove functions to clean up behavior.
Some code that I've simplified:
void Update()
{
if (canAct && !dead)
{
CheckTriggers();
PlayAllActions();
}
}
private void CheckTriggers()
{
for (int i = 0; i < actions.Length; i++)
{
switch (actions[i].trigger)
{
case ActionTrigger.Trigger.OnCollisionEnter:
if (isColliding)
AddActionList(actions[i].actionSetList);
else
RemoveActionList(actions[i].actionSetList);
break;
case ActionTrigger.Trigger.UponBeingAttacked:
if (hasBeenAttacked)
AddActionList(actions[i].actionSetList);
break;
}
}
}
public void AddActionList(ActionSetList actionSetList)
{
bool containsItem = existingActionsList.Any(item => item == actionSetList);
if (containsItem)
return;
existingActionsList.Add(actionSetList);
}
private void PlayAllActions()
{
if (existingActionsList.Count > 0)
for (int i = 0; i < existingActionsList.Count; i++)
ActionPlayEffect(existingActionsList[i]);
}
public void ActionPlayEffect(ActionSetList actionSetList)
{
for (int i = 0; i < actionSetList.Length; i++)
{
switch (actionSetList[i].type)
{
case ActionSet.Type.CastSpell:
if (spellRoutine == null && actionSetList[i].cooldownTimeRemaining <= 0)
spellRoutine = StartCoroutine(Cast(actionSetList[i]));
break;
case ActionSet.Type.PlayAnim:
if (!isInActionPose)
{
animator.SetTrigger("ActionTrigger");
animator.SetInteger("Action", (int)actionSetList[i].animToPlay+1);
isInActionPose = true;
}
break;
}
}
}
public void RemoveActionList(ActionSetList actionSetList)
{
bool containsItem = existingActionsList.Any(item => item == actionSetList);
if (containsItem)
{
ActionRemoveEffect(actionSetList);
existingActionsList.Remove(actionSetList);
}
}
public void ActionRemoveEffect(ActionSetList actionSetList)
{
for (int i = 0; i < actionSetList.Length; i++)
{
switch (actionSetList[i].type)
{
case ActionSet.Type.CastSpell:
CancelCast();
break;
case ActionSet.Type.PlayAnim:
animator.SetTrigger("ActionTrigger");
animator.SetInteger("Action", 0);
isInActionPose = false;
break;
}
}
}
What can I do to build a more efficient creature AI?
I would probably write a similar system using delegates.
A delegate can to some extent be considered a variable holding a list of methods. If you execute that delegate you then execute all the methods it holds.
This would allow you to add methods like this, to a list of methods that you then call when desired.
delegate void OnSpawn(GameObject gameObject); //Create delegate type
public OnSpawn onSpawn; //Create variable from delegate type
void SetUpStats(Gameobject gameObject){
//Set hp, initialize spells
}
void SetUpAnimations(GameObject gameObject){
//Initialize animations
}
void PlaySpawnSound(GameObject gameObject){
//Play a spawn sound
}
void Start(){
if (onSpawn == null) //Add content to delegate
{
onSpawn = new OnSpawn(SetUpStats); //You may be able to write onSpawn = SetUpStats; instead, for shorter code. But please test it.
onSpawn += SetUpAnimations;
onSpawn += PlaySpawnSound;
}
}
void Spawn(){
onSpawn(gameObject);
//Call delegate, invoking all methods stored in it.
//Note that they all receive the same input. In this case the gameObject.
//You can give them any input you want, so long as you define it in the delegate type.
//I chose a gameObject as you can get all components and more from it.
}
Let me know if you have any questions or things you wonder about.

Is this goto expressive?

The following code was a proof of concept for a message batching routine. Do I avoid goto like the plague and rewrite this code? Or do you think the goto is an expressive way to get this done?
If you'd rewrite please post some code...
var queue = new Queue<TraceItem>(this.batch);
while (this.connected)
{
byte[] buffer = null;
try
{
socket.Recv(out buffer);
}
catch
{
// ignore the exception we get when the socket is shut down from another thread
// the connected flag will be set to false and we'll break the loop
}
HaveAnotherMessage:
if (buffer != null)
{
try
{
var item = TraceItemSerializer.FromBytes(buffer);
if (item != null)
{
queue.Enqueue(item);
buffer = null;
if (queue.Count < this.batch && socket.Recv(out buffer, ZMQ.NOBLOCK))
{
goto HaveAnotherMessage;
}
}
}
catch (Exception ex)
{
this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
this.tracer.TraceException(TraceEventType.Error, 0, ex);
}
}
// queue processing code
}
Pretty much sums up my thoughts on "goto."
Goto is bad programming practice for many reasons. Chief among them is that there is almost never a reason for it. Someone posted a do..while loop, use that. Use a boolean to check if you should continue. Use a while loop. Goto's are for interpreted languages and a call back to assembler days (JMP anyone?). You're using a high level language for a reason. So that you and everyone else doesn't look at your code and get lost.
To keep this answer somewhat current I'd like to point out that a combination of goto and bracing errors caused a major SSL bug in iOS and OS X.
Replace the goto with a do-while, or simply a while loop if you don't want the "always run once" functionality you have right now.
var queue = new Queue<TraceItem>(this.batch);
while (this.connected)
{
byte[] buffer = null;
try
{
socket.Recv(out buffer);
}
catch
{
// ignore the exception we get when the socket is shut down from another thread
// the connected flag will be set to false and we'll break the loop
}
do {
if (buffer != null)
{
try
{
var item = TraceItemSerializer.FromBytes(buffer);
if (item != null)
{
queue.Enqueue(item);
buffer = null;
}
}
catch (Exception ex)
{
this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
this.tracer.TraceException(TraceEventType.Error, 0, ex);
}
}
} while(queue.Count < this.batch && socket.Recv(out buffer, ZMQ.NOBLOCK))
// queue processing code
}
It's so amazingly easy to rid yourself of GOTO in this situation it makes me cry:
var queue = new Queue<TraceItem>(this.batch);
while (this.connected)
{
byte[] buffer = null;
try
{
socket.Recv(out buffer);
}
catch
{
// ignore the exception we get when the socket is shut down from another thread
// the connected flag will be set to false and we'll break the loop
}
bool hasAnotherMessage = true
while(hasAnotherMessage)
{
hasAnotherMessage = false;
if (buffer != null)
{
try
{
var item = TraceItemSerializer.FromBytes(buffer);
if (item != null)
{
queue.Enqueue(item);
buffer = null;
if (queue.Count < this.batch && socket.Recv(out buffer, ZMQ.NOBLOCK))
{
hasAnotherMessage = true;
}
}
}
catch (Exception ex)
{
this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
this.tracer.TraceException(TraceEventType.Error, 0, ex);
}
}
}
// queue processing code
}
I guess the goto is SLIGHTLY more readable intuitively... But if you WANTED to avoid it I think all you'd have to do is throw the code in a while(true) loop, and then have a break statement at the end of the loop for a normal iteration. And the goto could be replaced with a continue statement.
Eventually you just learn to read and write loops and other control flow structures instead of using goto statements, at least in my experience.
Kind of related to Josh K post but I'm writing it here since comments doesn't allow code.
I can think of a good reason: While traversing some n-dimensional construct to find something. Example for n=3 //...
for (int i = 0; i < X; i++)
for (int j = 0; j < Y; j++)
for (int k = 0; k < Z; k++)
if ( array[i][j][k] == someValue )
{
//DO STUFF
goto ENDFOR; //Already found my value, let's get out
}
ENDFOR: ;
//MORE CODE HERE...
I know you can use "n" whiles and booleans to see if you should continue.. or you can create a function that maps that n-dimensional array to just one dimension and just use one while but i believe that the nested for its far more readable.
By the way I'm not saying we should all use gotos but in this specific situation i would do it the way i just mentioned.
You could refactor is to something like this.
while (queue.Count < this.batch && buffer != null)
{
try
{
var item = TraceItemSerializer.FromBytes(buffer);
buffer = null;
if (item != null)
{
queue.Enqueue(item);
socket.Recv(out buffer, ZMQ.NOBLOCK)
}
}
catch (Exception ex)
{
this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
this.tracer.TraceException(TraceEventType.Error, 0, ex);
}
}
Umm, I'm not really sure you want to goto out of a try block. I'm pretty sure that is not a safe thing to do, though I'm not 100% sure on that. That just doesn't look very safe...
Wrap the "HaveAnotherMessage" into a method that takes in the buffer and may call itself recursively. That would seem to be the easiest way to fix this.
I would avoid goto in this case, and refactor it. The method reads too long in my opinion.
I think your method is too big. It mixes different levels of abstraction, like error processing, message retrieval and message processing.
If you refactor it in different methods, the goto naturally goes away (note: I assume your main method is called Process):
...
private byte[] buffer;
private Queue<TraceItem> queue;
public void Process() {
queue = new Queue<TraceItem>(batch);
while (connected) {
ReceiveMessage();
TryProcessMessage();
}
}
private void ReceiveMessage() {
try {
socket.Recv(out buffer);
}
catch {
// ignore the exception we get when the socket is shut down from another thread
// the connected flag will be set to false and we'll break the processing
}
}
private void TryProcessMessage() {
try {
ProcessMessage();
}
catch (Exception ex) {
ProcessError(ex);
}
}
private void ProcessMessage() {
if (buffer == null) return;
var item = TraceItemSerializer.FromBytes(buffer);
if (item == null) return;
queue.Enqueue(item);
if (HasMoreData()) {
TryProcessMessage();
}
}
private bool HasMoreData() {
return queue.Count < batch && socket.Recv(out buffer, ZMQ.NOBLOCK);
}
private void ProcessError(Exception ex) {
ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
tracer.TraceException(TraceEventType.Error, 0, ex);
}
...

Restart Function That Is Running

I have a function that calls a test on each object. I want to be able to retest if the current test fails.
foreach (TestObject test in Tests)
{
test.RunTest()
}
//This is in the TestObject class
RunTest()
{
if (failure)
{
//Want to be able to run RunTest() again without interrupting the foreach loop.
}
}
You guys like too much code...
for (var tryCount = 0; tryCount < 3; tryCount++)
if (test.RunTest())
break;
... oh I thought of an even shorter version... but it's not as clean ...
for (var tryCount = 0; !test.RunTest() && tryCount < 3; tryCount++);
If you want reuse then something like this...
static bool RunTest(Func<bool> testCase, int maxRetry)
{
for (var tryCount = 0; tryCount < maxRetry; tryCount++)
if (testCase())
return true;
return false;
}
// usage
var testResult = RunTest(test.RunTest, 3);
// or even...
var testResult = RunTest(
{
try {
return test.RunTest();
} catch (Exception ex) {
Debug.WriteLine(ex);
return false;
}
}, 3);
For both answers above, the solutions will result in RunTest() running forever if the failure is legitimate (i.e. not a transient failure, which I can only guess is what you're hitting). You may consider doing one of the loops above, but instead keep a count of how many failures and bail out once that threshold is reached. Something like:
int FailureThreshold = 3;
foreach (TestObject test in Tests)
{
int failCount = 0;
while (failCount < FailureThreshold)
{
if (test.RunTest())
{
break;
}
else
{
failCount++;
}
}
}
You should also consider keeping statistics for how many times you need to loop in order to pass. This could be a great indicator of test stability.
There are several ways you could go about doing this, depending on why exactly you want to do this. You could:
1) Have RunTest() return boolean for success or failure, and then:
foreach (TestObject test in Tests)
{
while(!test.runTest(){}
}
2) Use a while inside of RunTest():
RunTest()
{
while(true)
{
...test stuff...
if(failure)
continue;
else
break;
}
}
foreach (TestObject test in Tests)
{
test.RunTest()
}
//This is in the TestObject class
RunTest()
{
//set it to failure or set variable to failure
while (failure)
{
//do the test
//if using variable set it to failure if it failed, success if it succeeded
//will keeping going through the while statement until it succeeds or you cut it off another way
}
// has succeeded
}

Categories

Resources