I have general questions about Managing selenium web project, the example is below, my question is how to manage those test cases?(its only 3 for the example, the real number of test cases is more than 1000)
Did create class for sub tests is good, like class for login and all the tests that related to log in is under this class?
Did there is an Conventions for writing test cases and manage them?
Thanks you all.
I create class with tests like:
#Test //Test1
public void logInFaildTest() {
GridTest gridTest = new GridTest();
WebDriver webDriver = gridTest.getWebDriver();
String url = gridTest.getUrl();
LoginPage logIn = new LoginPage(webDriver, url);
String userName = "user";
String pass="pass";
logIn.login(userName, pass);
WebElement errorMsg = webDriver.findElement(By.className("dijitToasterContent"));
String actual = errorMsg.getAttribute("innerHTML");
String expected="Incorrect user name or password. Please try again.";
assertEquals(expected, actual);
webDriver.close();
}
#Test
public void loginSucsecc()
{
GridTest gridTest = new GridTest();
String url = gridTest.getUrl();
WebDriver webDriver = gridTest.getWebDriver();
LoginPage logIn = new LoginPage(webDriver, url);
String userName = "user";
String pass="pass";
logIn.login(userName, pass);
String actual = webDriver.getCurrentUrl();
String expected= url+"#lastmile/";
// webDriver.close();
webDriver.quit();
assertEquals(expected, actual);
}
#Test
public void accountLock()
{
GridTest gridTest = new GridTest();
String url = gridTest.getUrl();
WebDriver webDriver = gridTest.getWebDriver();
LoginPage logIn = new LoginPage(webDriver, url);
String userName = "user";
String pass="wrong";
for(int i=0;i<11;i++){
logIn.login(userName, pass);
logIn.clearFileduNamePass();
}
WebElement msg = webDriver.findElement(By.id("dijit__TemplatedMixin_0")); //block message
String actual = msg.getAttribute("innerHTML");
int splitIndex= actual.indexOf(".<");
actual = actual.substring(0, splitIndex);
String expected= "Your account has been locked";
webDriver.quit();
assertEquals(expected, actual);
}
}
Yes what you've done is good only.So that all Login related operations can go into one class so if there is any change we can easily manage that
Object Maintaenance
You can go with Page Object Model(POM) as it is widely used approach and easily manageable one.This is for managing your Objects more like maintaining an Object Repository
As you can observe, all we are doing is finding elements and filling values for those elements.
This is a small script. Script maintenance looks easy. But with time test suite will grow. As you add more and more lines to your code, things become tough.
The chief problem with script maintenance is that if 10 different scripts are using the same page element, with any change in that element, you need to change all 10 scripts. This is time consuming and error prone.
A better approach to script maintenance is to create a separate class file which would find web elements , fill them or verify them. This class can be reused in all the scripts using that element. In future if there is change in the web element , we need to make change in just 1 class file and not 10 different scripts.
This approach is called Page Object Model(POM). It helps make code more readable, maintainable, and reusable.
Test Data Maintenance
The next you've to consider is the test data used to run the test cases with different set of data Test-Driven Approach
Same as POM You can create a factory class which will give you set of data whenever required so that when you want to change/modify the data you can simply go to the factory and change it .
For ex you create a class named LoginData which have functions like getValidCredentials getRandomCredentials to get your data. If your application requires random emailid for each run then you can simply modify the getValidCredentials part alone
It will help you a lot when your application runs mainly on forms or user datas
Reusable Components
The third thing is the Re-usability of what you've created.You can reuse the validLogin for other scenario's as well
Related
I'm building an automatic game client that is supposed to make moves against me in a 4-Wins-Game. For making a move it should chose a column and send that chosen column by calling the move() function to my server.
public class AutomaticGameClient {
private String userName;
private String userPassword;
public AutomaticGameClient(String userName, String userPassword) {
this.userName = userName;
this.userPassword = userPassword;
}
public int makeMove() {
columnNo = 0;
move(columnNo);
return columnNo;
}
}
Right now it always simply moves by making the next move in the first row (columnNo = 0). This works.
Now I have to test that function, but I don't want to test the move() part. I only want to assert, that it's returning 0:
#Test
public void whenMakeMove_columnNoIsZero() {
AutomaticGameClient agcY = new AutomaticGameClient("Georg1", "geheim1");
int rowMoved = agcY.makeMove();
assertEquals(rowMoved, 0);
}
When I run this test, I get org.java_websocket.exceptions.WebsocketNotConnectedException, because move(columnNo) is trying to start a connection to my socket. So is there a way to skip this part of the function under test?
"So is there a way to skip this part of the function under test?" - Yes. One could create a partial mock/spy of the unit under test and then mock the move(...)-method. For more details please refer to this posts by Victor Grazi and its answers.
In this concrete situation, however, the cleaner solution would be to move socket-related code to a separate service. A unit should be tested as a unit and thus we should use mocks seldomly and only if no other possibility exists. This, however, is a boundary between units, thus socket-communication should be moved in a separate unit for better testability. Please notice that I do not say that each class is a unit. A unit can be composed of multiple classes. But one class should not be composed of multiple units since we then have to resort to solutions like partial mocks for the unit under test. In my opinion, mocking the unit under test is always a red flag.
been a while since I have been here and am just trying to re-familiarize myself with my test automation framework I have been working on. Maybe a stupid question but I am going to throw it out there anyway as I think aloud.
Because I have introduced a config file which contains the path to an excel file(which contains test data) and implemented a basic excel reader to extract this data for testing I am finding that a great deal of my initial test is primarily taken up by all this set up.
For instance:
create an instance of a ReadPropertyFile class
Create an object of an ExcellDataConfig class and pass to it the location of the excel file from the config file
set the testcase id for this test to scan the excel file for where to start reading the data from the sheet - excel sheet contains markers
get the locations rol / col info from the sheet of all the interesting stuff i need for my test e.g. username / password, or some other data
open the browser
in the case of running a test on for multiple users set up a for loop that iterates through the excel sheet and logs in and then does the actual test.
Is a lot of configuration options but is there a simpler way?
I have a separate TestBase class which contains the login class and i thought to somehome move this user login info stuff there but not sure if that is such a good idea.
I just don't want to get bogged down duplicating work does anyone have any high level suggestions?
Here is a compilable (but not fully coded) quick-and-dirty example how you could design a base class for Selenium test classes. This follows the DRY principle (Don't Repeat Yourself).
The base class defines a login/logout method which would be called prior/after test execution of derived test classes.
Data is read from a Json file (based on javax.json) and used for locating elements (using the keys) and entering data (using the values). You can easily expand the code to support handling of other elements or location strategies (css, xpath).
Note that this example is not performance-optimised. But it is quick enough for a start and you could adapt it to your needs (e.g. eager data loading in a static context).
package myproject;
import java.io.*;
import java.util.*;
import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.*;
public class MyProjectBaseTest {
protected static WebDriver driver;
#Before
public void before() {
WebDriver driver = new FirefoxDriver();
driver.get("http://myapp");
login();
}
#After
public void after() {
logout();
}
private void login() {
Map<String, String> data = readData("/path/to/testdata/login.json");
Set<String> keys = data.keySet();
for (String key : keys) {
WebDriverWait wait = new WebDriverWait(driver, 20L);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(key)));
final WebElement we = driver.findElement(By.id(key));
if ("input".equals(we.getTagName())) {
we.clear();
we.sendKeys(data.get(key));
}
//else if "button".equals(we.getTagName())
}
}
private void logout() {
//logout code ...
}
private Map<String, String> readData(String filename) {
Map<String, String> data = new HashMap<String, String>();
InputStream is = null;
String key = null;
try {
is = new FileInputStream(filename);
JsonParser parser = Json.createParser(is);
while (parser.hasNext()) {
Event e = parser.next();
if (e == Event.KEY_NAME) {
key = parser.getString();
}
if (e == Event.VALUE_STRING) {
data.put(key, parser.getString());
}
}
parser.close();
}
catch (IOException e) {
//error handling
}
finally {
//close is
}
return data;
}
}
All this "setup work", you've described actually is pretty common stuff and it is how the AAA pattern really works:
a pattern for arranging and formatting code in UnitTest methods
For advanced Fixture usage you could utilize the most suitable for your case xUnit Setup pattern.
I totally agree with #Würgspaß's comment. What he is describing is called Object Map and I've used it heavily in the past 3 years with great success across multiple Automation projects.
I don't see in your scenario any usage of specific framework, so I would suggest that you pick some mature one, like TestNG in combination with Cucumber JVM. The last one will provide a Context injection, so you can get always clean step definition objects that can share context/state during the scenario run. And you will be able to reuse all the heavy setup just once and share it between all the tests. I/O operations are expensive and may cause issues in more complex cases, e.g. parallel execution of your tests.
As for the design of your code, you can find some of the Selenium's Test design considerations very useful, like the CallWrappers.
I want to call the Groovy scripts from Java and refresh the Groovy scripts periodically.
For example ,
public class AppTest {
public static void main(String args[]) throws Exception {
TestVO test = new TestVO();
AnotherInput input = new AnotherInput();
test.setName("Maruthi");
input.setCity("Newark");
GroovyClassLoader loader = new GroovyClassLoader(AppTest.class.getClassLoader());
Class groovyClass = loader.parseClass(new File("src/main/resources/groovy/MyTestGroovy.groovy"));
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
Object[] inputs = {test,null};
Map<String,String> result = (Map<String, String>)groovyObject.invokeMethod("checkInput", inputs);
System.out.println(result);
}
}
And my Groovy script is
class MyTestGroovy {
def x = "Maruthi";
def checkInput = { TestVO input,AnotherInput city ->
if(input.getName().equals(x)) {
input.setName("Deepan");
println "Name changed Please check the name";
} else {
println "Still Maruthi Rocks";
}
Map<String, String> result = new HashMap<String,String>();
result.put("Status", "Success");
if(city != null && city.getCity().equalsIgnoreCase("Newark")) {
result.put("requested_State", "Newark");
}
return result;
}
def executeTest = {
println("Test Executed");
}
}
How efficient my memory would be managed when I create multiple instances of groovy script and execute the script. Is it advisable to use a number of Groovy scripts as my customized rule engine. Please advise.
It is usually better to have several instances of the same script, than parsing the class every time you want to create an instance. Performance wise that is because compiling the script takes some time, you have to pay in addition to creating an instance. Memory wise you use up the number of available classes up faster. Even if old classes are collected, if you have many scripts active, it can happen... though that normally means hundreds or even thousands of them (depends on the jvm version and your memory settings)
Of course, once the script changed, you will have to recompile the class anyway. So if in your scenario you will have only one instance of the class active at the same time, and a new instance is only required after a change to the source, you can recompile every time.
I mention that especially, because you might even be able to write the script in a way, that let's you reuse the same instance. But it is of course beyond the scope of this question.
So I'm tesing using Junit, quite new to it.
I am trying to test methods in a class called SetOfUsers as follows:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "";
SetOfUsers instance = new SetOfUsers();
User expResult = null;
User result = instance.findUserByName(name);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
}
So I wanted to check the name of a user entered in Bob for instance in the name string like this
String name = "Bob";
since I have a user called Bob in the setOfUsers class.
The output window displays this message
Failed: expected:<null> but was:<Staff name:Bob, Staff pass:abc123>
What can I do to make this a pass?
Read about BDD, this is very nice technique for making tests easy to write and understand (read)
Test-driven development is a software development methodology which essentially states that for each unit of software, a software developer must:
define a test set for the unit first;
then implement the unit;
finally verify that the implementation of the unit makes the tests succeed.
Well written test should have GivenWhenThen sections
(Given) some context
(When) some action is carried out
(Then) a particular set of observable consequences should obtain
This style is known as SpecificationByExample
Given-When-Then is a style of representing tests - or as its advocates would say - specifying a system's behavior using SpecificationByExample.
Example test
#Test
public void testFindUserByName() {
// given
SetOfUsers instance = new SetOfUsers();
// when
User result = instance.findUserByName("Bob");
// then
assertEquals("Bob", result.getName());
}
Nice to read:
Arrange Act Assert Alternatives
Maintainable Tests
This test is always going to fail because the last line is
fail("The test case is a prototype.");
The reason your test is failing now is because of the line above,
assertEquals(expResult, result);
You are setting your expected result to null and the result you are getting from the name, "", is probably an empty String as well from that error message. You need to have expResult to be the same as what you expect instance.findUserByName("Bob") to return. However, unless you initialize the instance to be set with a User Object the objects will not match, so it might be better to either mock it to return a pre-created User object so they match, or create a User object with the same properties as the one you expect to be returned check the fields of the User Object returned and the User object you created to be sure they match.
If you want to check for what the user for Bob is, change the code to this:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "Bob";
SetOfUsers instance = new SetOfUsers();
User expResult = <Create an object you expect instance.findUserByName("Bob") to return>;
User result = instance.findUserByName(name);
//Check fields here.
assertEquals(expResult.getUserName(), result,getUserName());
// TODO review the generated test code and remove the default call to fail.
}
You can't test for null using assertEquals().
To test for null, use:
assertNull(result);
I don't understand the question, but if you want to search for "Bob" why you initialize name=""? The test should be:
#Test
public void testFindUserByName() {
//Create SetOfUsers
//Add new User with name Bob
//FindByUsername("Bob")
//AssertEqual(User.getName(), "Bob")
}
I am trying to find an HTML template solution for a Java web application. I need the flexibility to load templates from whatever sources I choose as most of them will likely be in a custom database. In my search I stumbled upon StringTemplate 4, however all of the examples I see require that the user put template files on disk.
I have noticed that STGroup can be instantiated without specifying a file or directory, however using the defineTemplate method does not seem to be a substitute for using file based templates. Unfortunately in all my tests with defineTemplate I have failed to get attributes to work. This all feels like I'm guessing in the dark.
Is StringTemplate the right library for this? Is there another one that would work better?
I'm starting to consider developing my own.
I figured it out...
import org.stringtemplate.v4.*;
import net.sf.json.*;
class STExampleApp {
public static void main(String args[]) {
String template = "decl(type, name, value) ::= \"<type> <name><init(value)>;\"\n"
+ "init(v) ::= \"<if(v)> = <v><endif>\"";
STGroup views = new STGroupString(template);
ST decl = views.getInstanceOf("decl");
decl.add("type", "int");
decl.add("name", "x");
decl.add("value", 12);
System.out.println(decl.render());
}
}
No file loading necessary. I learned this from: How to format decimal numbers with StringTemplate (ST) in Java?
I would just pass the template to a ST() constructor like this:
#Test public void testNullAttr() throws Exception {
String template = "hi <name>!";
ST st = new ST(template);
String expected =
"hi !";
String result = st.render();
assertEquals(expected, result);
}