I work as an automation engineer for my company. Recently, I wrote a piece of code that my manager absolutely would not accept.
I was asked to write some scripts for test cases involving different pieces of the GUI. The part of the code my manager would not accept was an if/else statement meant to check the current language of the prompt in the GUI.
I've been instructed to use Sikuli, and as such, it is very important that I know what language the application is currently set to so my scripts can click the correct buttons (which change depending on the language).
My thoughts were that the code iterates through the if/else statement and then points to the correct button. Example: The if/else statement determines that the "ok" button is currently the Suomi translation, so it will than click the correct button.
Here is an example of my code:
switch (button) {
case "ok":
if (s.exists("imagerepo/language/catalan_ok.png") != null) {
s.click("imagerepo/language/catalan_ok.png");
} else if (s.exists("imagerepo/language/suomi_ok.png") != null) {
s.click("imagerepo/language/suomi_ok.png");
} else if (s.exists("imagerepo/language/italian_ok.png") != null) {
s.click("imagerepo/language/italian_ok.png");
} else if (s.exists("imagerepo/language/portuguese_ok.png") != null) {
s.click("imagerepo/language/portuguese_ok.png");
} else if (s.exists("imagerepo/language/english_ok.png") != null) {
s.click("imagerepo/language/english_ok.png");
} else if (s.exists("imagerepo/language/dutch_ok.png") != null) {
s.click("imagerepo/language/dutch_ok.png");
} else if (s.exists("imagerepo/language/spanish_ok.png") != null) {
s.click("imagerepo/language/spanish_ok.png");
} else if (s.exists("imagerepo/language/french_ok.png") != null) {
s.click("imagerepo/language/french_ok.png");
} else if (s.exists("imagerepo/language/latina_ok.png") != null) {
s.click("imagerepo/language/latina_ok.png");
} else if (s.exists("imagerepo/language/chinese_ok.png") != null) {
s.click("imagerepo/language/chinese_ok.png");
}
break;
...etc..
My only gripe with the above code is that it is pretty ugly. Functionally it does exactly what I'd like it to, 100% of the time.
EDIT: I figure that having a switch that adapts to the potentially changing button would be better than having 10 switches for the same button. Arguably, against what I just said, if I'm writing the scripts, I will always know what language the system is going to be in.
If this is an example of poor code, what could I do instead to determine which "form" of the button I need to press?
It would be worth noting now that the answer I'm looking for does not actually pertain to testing at all, but rather, how do I optimally perform the function of that if/else block above?
Something like:
String[] languages = {
"catalan_ok.png",
"suomi_ok.png",
//...
}
for (String base : languages) {
String file = String.format("imagerepo/language/%s", base);
if (s.exists(file) != null) {
s.click(file);
break;
}
}
perhaps? Not tested.
I'm assuming that this is for internationalization so you could use a properties file for each language and then get the image path like this
ResourceBundle bundle = ResourceBundle.getBundle( "messages", userLocale );
s.click(bundle.getString("image"));
Related
I have a big chuck of code witch looks like this
if(!Click(By.linkText("HR Development"))){return;}
if(!Click(By.linkText("ISTQB Agile Tester Extension ( 1/2)"))){return;}
The idea is that the Click function returns true if the click succeeds and false otherwise.
There are also other functions like this outside the click function
does someone know a nicer way to get the same result?
So why not just
return boolean_expression();
whatever that expression evaluates, gets returned.
e.g.
if (foo == bar) {
return true;
} else {
return false;
}
can simply be
return (foo == bar);
You could recast to the equivalent
if (
!Click(By.linkText("HR Development")) ||
!Click(By.linkText("ISTQB Agile Tester Extension ( 1/2)"))
){
return;
}
Note that evaluation of || stops once the result is known. (This is called short-circuitting.)
Littering your functions with many return; statements can make debugging difficult as it can become difficult to set reliable breakpoints.
I have a big chuck of code witch [sic] looks like this
That's your problem. It looks like you've written one click handling class for many events.
Another idea might be to create individual handlers for events and have custom behavior as needed. That would be a more object-oriented approach.
Just make boolean variables out your conditions, and test with a || (or) operator:
boolean foo = !Click(By.linkText("HR Development"));
boolean bar = !Click(By.linkText("ISTQB Agile Tester Extension ( 1/2)"));
if (foo || bar) {
return;
}
It's clean, and if needed, you can add as many variables as you want.
Our team's Java Coding Guideline says:
Avoid using "!" in if statement as much as possible.
I have asked other colleagues, but no one gave me clear ideas why, because the guideline was created a long time ago and the author might have left our company.
Do you have any idea?
With the information provided, this calls for some speculation. One possible reason is that the intent was not for an if-statement by itself but for an if-else statement. In that case, I can see where you might say that you should reverse the cases so that you don't have the extra operation of the negation. Instead of
if (! boolVar) {
// Something
} else {
// Something else
}
you might prefer
if (boolVar) {
// Something else
} else {
// Something
}
Whether this is worth it or not is probably more a matter of taste and standardization than anything else.
The rule is likely an adaptation from Robert Martin's Clean Code, page 302:
Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives. For example:
if(buffer.shouldCompact())
is preferable to
if(!buffer.shouldNotCompact())
As an example, suppose you're creating a validator that requires two things to be false for the entity to be valid:
The entity must not have been created within the last 12 hours, and
The entity's bank account total sum must not exceed $50,000.
Naturally the idea would be to write two methods for this:
boolean isCreatedWithinLastTwelveHours(BankAccount account)
boolean hasMoreThanTotalSumCap(BankAccount account)
...at which point, you then invoke these as:
boolean newAccount = isCreatedWithinTheLastTwelveHours(account);
boolean highEndAccount = hasMoreThanTotalSumCap(account);
if(!newAccount && !highEndAccount) { // ... other logic
// The more astute would use DeMorgan's law in an effort to make this more readable
if(!(newAccount || highEndAccount)) { // other logic
Well...wouldn't it be nicer if you just said what they weren't instead?
boolean isNotCreatedWithinLastTwelveHours(BankAccount account)
boolean hasLessThanTotalSumCap(BankAccount account)
That'd make the expression a bit more concise:
if(notNewAccount && notHighEndAccount) { // .. carry on!
Of course "!" can be used when you like. There is no "unless" in java and you have no other choices in some conditions.
Looks like yet-another-useless-rule. Generally speaking, there are no absolute terms in this scenario, true that if you are in a if-else clause then possibly it is better to write
if(myCondition) {
doThis()
} else {
doSomethingElse()
}
Instead of
if(!myCondition) {
doSomethingElse()
} else {
doThis()
}
However, that said, in some scenarios is actually quite ok to use the negation operator, particularly if no else clause is provided, example
if (!tokenDoesCompute()) {
throw InvalidTockenException("Whatever")
}
And actually in that scenario, using "!" makes quite a bit of sense for me.
Finally, if no one can really explain WHY the rule is there, maybe it is time to remove it, the only good reason I could find for it would be to provide consistency regarding the code style.
Okay, I answer my own question.
As other say, maybe this is written for the readability.
In The Art of Readable Code (p. 72) says:
Prefer dealing with the positive case first instead of the negative-e.g., if(debug) instead of if(!debug)
I found below post as well:
Readable Code - Remove Checking null
bool func(String name)
{
if ( (name != null) && (name.equals("true") ) {
//...
} else {
//...
}
}
bool func(String name)
{
if ( "true".equals(name) ) {
//...
} else {
//...
}
}
Ofcourse you can use the negation operator ! whenever you like.
However, if you have a situation where you have to write some actions in both if and else block then the following is more readable :
if(status){
//do something
}
else{
//do something else
}
than
if(!status){
//do something
}
else{
//do something else
}
But if you have situation where you only need to perform certain actions based on just one condition, i.e. if you have only an if block & no else block, then it is reasonably fine to use ! in if
I haven't seen anyone else suggest this, which is probably because they hate it as much as I do, but I'm showing it for completeness.
// Using not operator (preferred)
if (! someTest) { ... }
// Using compact not operator (kind of hides it)
if (!someTest) { ... }
// Comparing to false (ok, explicitly states what you want)
if (someTest == false) { ... }
// Comparing to true (a bit obscure)
if (someTest != true) { ... }
They all do the same, but please keep using !, just make sure you add a space after it, so it's easier to see.
So i'm trying to make a text game in java for a project and i have a problem in the main loop.I have the available commands in a hashmap named commands in the class CommandWords and i want to check if the user input exists in the hashmap and if it does to execute the associated object.But i can't exactly find a way.Here is my code.I understand it's probably an if but i don't know how to check.
public void play()
{
System.out.println("Welcome to the world of JZork " +player.name);
printWelcome();
boolean finished = false;
while (! finished) {
Command command = parser.getCommand();
if(command == null) {
System.out.println("I don't understand...");
}
}
}
It is possible to do it the way you said, but you would need to learn to use Java reflection. This isn't THAT hard, but you aren't going to like it.
if (command.equals("quit")) {
quit();
}
else if (command.equals("whatever")) {
whatever();
}
This isn't that elegant, but it's easy to implement.
I have a ITextViewer object and from that the StyledText widget in which Eclipse displays code. I want to hihglight one single line that is defined by the line number. Therefore I added a LineBackgroundListener to the StyledText object an wrote the following code:
private class HighlightLine implements LineBackgroundListener {
#Override
public void lineGetBackground(LineBackgroundEvent event) {
if (lineToHighlight != -1) {
int line = ((StyledText) event.widget).getLineAtOffset(event.lineOffset);
if (line == lineToHighlight) {
event.lineBackground = styledText.getSelectionBackground();
} else if (line == previousLineToHighlight) {
event.lineBackground = styledText.getBackground();
}
styledText.redraw();
styledText.update();
}
}
}
This work more or less fine, but the problem is, it very much slows down Eclipse. It's probably the case because it has to update the Widget very often and that's not optimal. However, I couldn't think of another way to to it after a lot of trials. Any idea?
You don't need these (expensive) calls:
styledText.redraw();
styledText.update();
lineGetBackground is called during the draw line operation so it does not need a redraw or update.
Note: If the StyledText control has any StyleRange ranges they may override the background.
In my program I have two classes, one called GlassPiece, and one called TrackerChip.
These two objects are always "strongly connected", that is, no two GlassPieces can share a TrackerChip, and no two TrackerChips can share a GlassPiece. Therefore in my setter methods, I need to take care to disconnect any old references hanging around, as so:
public class TrackerChip
{
GlassPiece linkedGlassPiece;
public void setGlassPiece(GlassPiece newGlassPiece)
{
GlassPiece oldGlassPiece = linkedGlassPiece;
linkedGlassPiece = newGlassPiece;
if(oldGlassPiece != null)
{
oldGlassPiece.setTrackerChip(null); //disconnect old GlassPiece
}
if(linkedGlassPiece != null && linkedGlassPiece.getTrackerChip() != this)
{
linkedGlassPiece.setTrackerChip(this); //update counterpart
}
}
}
and the method GlassPiece.setTrackerChip(TrackerChip) works exaxctly the same way.
The thing is, the above code doesn't actually work, and strange stuff happens when trying to manage linking between several different GlassPieces and TrackerChips. However, if I replace the last part with:
if(newGlassPiece != null && newGlassPiece.getTrackerChip() != this)
{
newGlassPiece.setTrackerChip(this);
}
Then everything works properly. This seems very strange to me (all I did was replaced linkedGlassPiece, the instance variable, with newGlassPiece, the parameter). But early in the method I set the references equal to each other! Why does the first method not work?
P.S. I can confirm there is no infinite loop in the method.
As for why this isn't working, you're right, it won't hit an endless loop, but it's not going to do what you expect.
You enter setGlassPiece, linkedGlassPiece for this object is set to the value of newGlassPiece.
Then it calls setTrackerChip(null) on the oldGlassPiece.
The oldGlassPiece still has a reference to the original TrackerChip, so it calls setGlassPiece(null), which sets linkedGlassPiece to null that you just set on the TrackerChip, and calls setTrackerChip(null) on the NEW GlassPiece as well.
I honestly can't think of a way to get it to work the way you're going. You would have to add some additional parameters such that it would no longer be re-entrant. Namely, when you call setTrackerChip on the oldGlassPiece, it's not going to turn around and call the same TrackerChip back setting its reference to null. Perhaps just a boolean flag that would indicate that it should not null out the second level references.
Here's some code:
public class TrackerChip
{
GlassPiece linkedGlassPiece;
public void setGlassPiece(GlassPiece newGlassPiece)
{
setGlassPiece(newGlassPiece, true);
}
public void setGlassPiece(GlassPiece newGlassPiece, boolean reentrant)
{
GlassPiece oldGlassPiece = linkedGlassPiece;
linkedGlassPiece = newGlassPiece;
if(reentrant && oldGlassPiece != null)
{
oldGlassPiece.setTrackerChip(null, false); //disconnect old GlassPiece
}
if(linkedGlassPiece != null && linkedGlassPiece.getTrackerChip() != this)
{
linkedGlassPiece.setTrackerChip(this); //update counterpart
}
}
}
Instead of taking this approach, I would recommend just having a pair of static HashMaps that manage the relationships. That would probably be far simpler. There could be thread safety issues if your use case is not single threaded, but you'd just need to synchronize the method that sets it up. Maybe create a relationship management object as follows:
public class RelationshipMgr {
HashMap<GlassPiece, TrackerChip> gpMap;
HashMap<TrackerChip, GlassPiece> tcMap;
public void setRelationship(GlassPiece gp, TrackerChip tc) {
gpMap.put(gp, tc);
tcMap.put(tc, gp);
}
}
Actually, in the Google Guava library, there is even a class ready to use for this sort of thing called BiMap, check it out.
If there is always a one to one relationship, it might be worthwhile to consider merging those classes into one.
This should work I think:
public class TrackerChip {
GlassPiece linkedGlassPiece;
public void setGlassPiece(GlassPiece newGlassPiece) {
if (linkedGlassPiece == newGlassPiece) {
return;
}
if (linkedGlassPiece != null) {
GlassPiece tmp = linkedGlassPiece;
linkedGlassPiece = null;
tmp.setTrackerChip(null);
}
if (newGlassPiece != null) {
linkedGlassPiece = newGlassPiece;
linkedGlassPiece.setTrackerChip(this);
}
}
}