Friday 12 January 2018

Appium Sample script and Setup procedure for Android Mobile Automation

Appium
Introduction:
         Appium is an open-source tool for automating native, mobile web, and hybrid applications on iOS and Android platforms. Native apps are those written using the iOS or Android SDKs. Mobile web apps are web apps accessed using a mobile browser (Appium supports Safari on iOS and Chrome or the built-in ‘Browser’ app on Android). Hybrid apps have a wrapper around a “webview” – a native control that enables interaction with web content.
                                    http://appium.io/introduction.html

Appium Design:
        1. Vendor-provided automation frameworks under the hood:
o   iOS: Apple’s UIAutomation
o   Android 4.2+: Google’s UiAutomator
o   Android 2.3+: Google’s Instrumentation. (Instrumentation support         is provided by bundling a separate project, Selendroid)
2. Wrapping the vendor-provided frameworks in one API, the WebDriver           API. WebDriver (aka “Selenium WebDriver”) specifies a client-server      protocol (known as the JSON Wire Protocol). Given this client-server    architecture, a client written in any language can be used to send the       appropriate HTTP requests to the server. Appium & WebDriver clients           are not technically “test frameworks” – they are “automation      libraries”. You can manage your test environment any way you like!
Requirement:
         IOS REQUIREMENTS
o   Mac OS X 10.9.2 recommended
o   XCode >=  5.1.1 recommended
o   Apple Developer Tools (iPhone simulator SDK, command line tools)
            ANDROID REQUIREMENTS
o   Android SDK API >= 17 (Additional features require 18/19)
Setup:
         Running Appium on iOS:
         Appium on OS X supports iOS and Android testing.
o   Appium requires Mac OS X 10.9 is recommended.
o   Make sure you have Xcode and the iOS SDK(s) installed. Xcode version 5.1 is recommended.
o   Using Appium.app, you can authorize iOS through the GUI.
            Check the below: 
o   If you’re on Xcode 6, you need to launch each simulator you intend to use with appium in advance, and change the default to actually show the      soft keyboard if you want sendKeys to work. You can do this by clicking on any textfield and hitting command-K until you notice the soft keyboard show up.
o   If you’re on Xcode 6, you have a feature in Xcode called Devices (command-shift-2). You need to make sure that whichever deviceName             you choose to use with Appium in your capabilities, there is only one of those per sdk version. In other words, if you send in a deviceName cap of          “iPhone 5s” and a platformVersion cap of “8.0”, you need to make sure    that there is exactly one device with the name “iPhone 5s” and the 8.0        sdk in your devices list. Otherwise, Appium won’t know which one to use.
o   In iOS8, devices each have their own setting which enables or disables UIAutomation. It lives in a “Developer” view in the Settings app. You             need to verify that UIAutomaion is enabled in this view before the            simulator or device can be automated.
          Running Appium on Android:
                    If you are running Appium on Windows, you can use the Appium.exe client, which will allow you to quickly launch an Appium          server and use the Inspector. You will not be able to test iOS apps on a    locally hosted server, because Appium relies on OS X-only libraries to             support iOS testing. You can however use the Remote Server option to    connect to an Appium server running on a Mac.
Deploying an iOS app to a real device:
To prepare for your Appium tests to run on a real device, you will need to:
o   Build your app with specific device-targeted parameters
o   Use fruitstrap, a 3rd-party tool, to deploy this build to your device
Deploying an Android app to a real device:

Appium GUI:
iOS:
Android:
Sample Code:
 (Android Native App)
public class AndroidTest {
    private AppiumDriver driver;
    @Before
    public void setUp() throws Exception {
        File classpathRoot = new File(System.getProperty("user.dir"));
        File appDir = new File(classpathRoot, "../../../apps/ApiDemos/bin");
        File app = new File(appDir, "ApiDemos-debug.apk");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("device","Android");
        capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
        capabilities.setCapability(CapabilityType.VERSION, "4.4");
        capabilities.setCapability("app", app.getAbsolutePath());
        capabilities.setCapability("app-package", "com.example.android.apis");
        capabilities.setCapability("app-activity", ".ApiDemos");
        driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
    }
    @After
    public void tearDown() throws Exception {
        driver.quit();
    }
    @Test
    public void apiDemo(){
        WebElement el = driver.findElement(By.name("Animation"));
        assertEquals("Animation", el.getText());
        el = driver.findElementByClassName("android.widget.TextView");
        assertEquals("API Demos", el.getText());
        el = driver.findElement(By.name("App"));
        el.click();
        List<WebElement> els = driver.findElementsByClassName("android.widget.TextView");
        assertEquals("Activity", els.get(2).getText());
    }

(iOS Native App)
public class UICatalogTest {
    private AppiumDriver driver;
    private WebElement row;
    @Before
    public void setUp() throws Exception {
        // set up appium
        File classpathRoot = new File(System.getProperty("user.dir"));
        File appDir = new File(classpathRoot, "../../../apps/UICatalog/build/Release-iphonesimulator");
        File app = new File(appDir, "UICatalog.app");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
        capabilities.setCapability(CapabilityType.VERSION, "7.1");
        capabilities.setCapability(CapabilityType.PLATFORM, "Mac");
        capabilities.setCapability("device", "iPhone Simulator");
        capabilities.setCapability("app", app.getAbsolutePath());
        driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
    }
    @After
    public void tearDown() throws Exception {
        driver.quit();
    }
    private void openMenuPosition(int index) {
        //populate text fields with two random number
        MobileElement table = new MobileElement((RemoteWebElement)driver.findElementByClassName("UIATableView"), driver);
        row = table.findElementsByClassName("UIATableCell").get(index);
        row.click();
    }
    private Point getCenter(WebElement element) {
      Point upperLeft = element.getLocation();
      Dimension dimensions = element.getSize();
      return new Point(upperLeft.getX() + dimensions.getWidth()/2, upperLeft.getY() + dimensions.getHeight()/2);
    }
    @Test
    public void testFindElement() throws Exception {
        //first view in UICatalog is a table
        MobileElement table = new MobileElement((RemoteWebElement)driver.findElementByClassName("UIATableView"), driver);
        assertNotNull(table);
        //is number of cells/rows inside table correct
        List<WebElement> rows = table.findElementsByClassName("UIATableCell");
        assertEquals(12, rows.size());
        //is first one about buttons
        assertEquals("Buttons, Various uses of UIButton", rows.get(0).getAttribute("name"));
        //navigationBar is not inside table
        WebElement nav_bar = null;
        try {
            nav_bar = table.findElementByClassName("UIANavigationBar");
        } catch (NoSuchElementException e) {
            //expected
        }
        assertNull(nav_bar);
        //there is nav bar inside the app
        driver.getPageSource();
        nav_bar = driver.findElementByClassName("UIANavigationBar");
        assertNotNull(nav_bar);
    }
    @Test
    public void test_location() {
        //get third row location
        row = driver.findElementsByClassName("UIATableCell").get(2);
        assertEquals(0, row.getLocation().getX());
        assertEquals(152, row.getLocation().getY());
    }
    @Test
    public void testScreenshot() {
        //make screenshot and get is as base64
        WebDriver augmentedDriver = new Augmenter().augment(driver);
        String screenshot = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.BASE64);
        assertNotNull(screenshot);
        //make screenshot and save it to the local filesystem
        File file = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
        assertNotNull(file);
    }

    @Test
    public void testTextFieldEdit() {
        //go to the text fields section
        openMenuPosition(2);
        WebElement text_field = driver.findElementsByClassName("UIATextField").get(0);
        //get default/empty text
        String default_val = text_field.getAttribute("value");
        //write some random text to element
        String rnd_string = RandomStringUtils.randomAlphanumeric(6);
        text_field.sendKeys(rnd_string);
        assertEquals(rnd_string, text_field.getAttribute("value"));
        //send some random keys
        String rnd_string2 = RandomStringUtils.randomAlphanumeric(6);
        Actions swipe = new Actions(driver).sendKeys(rnd_string2);
        swipe.perform();
        //check if text is there
        assertEquals(rnd_string + rnd_string2, text_field.getAttribute("value"));
        //clear
        text_field.clear();
        //check if is empty/has default text
        assertEquals(default_val, text_field.getAttribute("value"));
    }
    @Test
    public void testAlertInteraction() {
        //go to the alerts section
        openMenuPosition(10);
        //trigger modal alert with cancel & ok buttons
        List<WebElement> triggerOkCancel = driver.findElementsByAccessibilityId("Show OK-Cancel");
        triggerOkCancel.get(1).click();
        Alert alert = driver.switchTo().alert();
        //check if title of alert is correct
        assertEquals("UIAlertView <Alert message>", alert.getText());
        alert.accept();
    }

    @Test
    public void testScroll() {
        //scroll menu
        //get initial third row location
        row = driver.findElementsByClassName("UIATableCell").get(2);
        Point location1 = row.getLocation();
        Point center = getCenter(row);
        //perform swipe gesture
        driver.swipe(center.getX(), center.getY(), center.getX(), center.getY()-20, 1);
        //get new row coordinates
        Point location2 = row.getLocation();
        assertEquals(location1.getX(), location2.getX());
        assertNotSame(location1.getY(), location2.getY());
    }
    @Test
    public void testSlider() {
      //go to controls
      openMenuPosition(1);
      //get the slider
      WebElement slider = driver.findElementByClassName("UIASlider");
      assertEquals("50%", slider.getAttribute("value"));
      Point sliderLocation = getCenter(slider);
      driver.swipe(sliderLocation.getX(), sliderLocation.getY(), sliderLocation.getX()-100, sliderLocation.getY(), 1);
      assertEquals("0%", slider.getAttribute("value"));
    }
    @Test
    public void testSessions() throws Exception {
      HttpGet request = new HttpGet("http://localhost:4723/wd/hub/sessions");
      HttpClient httpClient = new DefaultHttpClient();
      HttpResponse response = httpClient.execute(request);
      HttpEntity entity = response.getEntity();
      JSONObject jsonObject = (JSONObject) new JSONParser().parse(EntityUtils.toString(entity));

      String sessionId = driver.getSessionId().toString();
      assertEquals(jsonObject.get("sessionId"), sessionId);
    }
    @Test
    public void testSize() {
        Dimension table = driver.findElementByClassName("UIATableView").getSize();
        Dimension cell = driver.findElementsByClassName("UIATableCell").get(0).getSize();
        assertEquals(table.getWidth(), cell.getWidth());
        assertNotSame(table.getHeight(), cell.getHeight());
    }
    @Test
    public void testSource() {
        //get main view soruce
        String source_main = driver.getPageSource();
        assertTrue(source_main.contains("UIATableView"));
        assertTrue(source_main.contains("TextFields, Uses of UITextField"));

        //got to text fields section
        openMenuPosition(2);
        String source_textfields = driver.getPageSource();
        assertTrue(source_textfields.contains("UIAStaticText"));
        assertTrue(source_textfields.contains("TextFields"));

        assertNotSame(source_main, source_textfields);
    }

(Android Web App)
public class ChromeTest {

    private WebDriver driver;

    /**
     * Instantiates the {@link #driver} instance by using DesiredCapabilities which specify the
     * 'iPhone Simulator' device and 'Chrome' app.
     * @throws Exception
     */
    @Before
    public void setUp() throws Exception {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("device", "Android");
        capabilities.setCapability("platformName", "android");
        capabilities.setCapability("version", "4.4");
        capabilities.setCapability("browserName", "chrome");
        driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"),
                capabilities);
        //driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }

    /**
     * Navigates to http://saucelabs.com/test/guinea-pig and interacts with the browser.
     *
     * @throws Exception
     */
    @Test
    public void runTest() throws Exception {
        driver.get("http://saucelabs.com/test/guinea-pig");
        Thread.sleep(1000);
        WebElement idElement = driver.findElement(By.id("i_am_an_id"));
        assertNotNull(idElement);
        assertEquals("I am a div", idElement.getText());
        WebElement commentElement = driver.findElement(By.id("comments"));
        assertNotNull(commentElement);
        commentElement.sendKeys("This is an awesome comment");
        WebElement submitElement = driver.findElement(By.id("submit"));
        assertNotNull(submitElement);
        submitElement.click();
        Thread.sleep(7000);
        WebElement yourCommentsElement = driver.findElement(By.id("your_comments"));
        assertNotNull(yourCommentsElement);
        assertTrue(driver.findElement(By.id("your_comments")).getText().contains("This is an awesome comment"));

      System.out.println(driver.getCurrentUrl());
    }

    /**
     * Closes the {@link #driver} instance.
     *
     * @throws Exception
     */
    @After
    public void tearDown() throws Exception {
        driver.quit();
    }
}

(iOS Web App)
public class SafariTest {

    private WebDriver driver;

    /**
     * Instantiates the {@link #driver} instance by using DesiredCapabilities which specify the
     * 'iPhone Simulator' device and 'safari' app.
     * @throws Exception
     */
    @Before
    public void setUp() throws Exception {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("device", "iPhone Simulator");
        capabilities.setCapability("platformName", "iOS");
        capabilities.setCapability("version", "7.1");
        capabilities.setCapability("browserName", "safari");
        driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"),
                capabilities);
        //driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }

    /**
     * Navigates to http://saucelabs.com/test/guinea-pig and interacts with the browser.
     *
     * @throws Exception
     */
    @Test
    public void runTest() throws Exception {
        driver.get("http://saucelabs.com/test/guinea-pig");
        Thread.sleep(1000);
        WebElement idElement = driver.findElement(By.id("i_am_an_id"));
        assertNotNull(idElement);
        assertEquals("I am a div", idElement.getText());
        WebElement commentElement = driver.findElement(By.id("comments"));
        assertNotNull(commentElement);
        commentElement.sendKeys("This is an awesome comment");
        WebElement submitElement = driver.findElement(By.id("submit"));
        assertNotNull(submitElement);
        submitElement.click();
        Thread.sleep(7000);
        WebElement yourCommentsElement = driver.findElement(By.id("your_comments"));
        assertNotNull(yourCommentsElement);
        assertTrue(driver.findElement(By.id("your_comments")).getText().contains("This is an awesome comment"));

      System.out.println(driver.getCurrentUrl());
    }

    /**
     * Closes the {@link #driver} instance.
     *
     * @throws Exception
     */
    @After
    public void tearDown() throws Exception {
        driver.quit();
    }
}


Advance Options:
          

Thursday 4 January 2018

Spring Framework Topics - JEE

I am writing this blog just to verify the concepts of Spring :

Spring MVC is one of the well know framework to develop Web applications. There are lot of enhancements which are done to Spring MVC V3.0, like Spring Boot, Spring Cloud, Spring V4.0 and it's completely open source for developing Enterprise applications.

The important concepts in Spring are :

  • Spring Context : For dependency injection(DI)
  • Spring DAO : For database operation using DAO Pattern
  • Spring JDBC : Foor JDBC and Datasource support
  • Spring ORM : For ORM Tool support such as Hibernate
  • Spring AOP: For Aspect Oriented Programming 
  • Spring Web module: For creating web application.

Advantages of Spring Framework:

Light weight : Spring is light weight, basic version of Spring is 2 MB.
DI/IOC : This helps to achieve loose coupling by wiring independent components/objects.
Spring Container : contains and manages life cycle of application
Transaction Management : Spring Supports transaction management, i.e, JDBC, File upload, Exception handling ..etc.either by spring annotation or bean configuration.
Exception Handling : Spring provide convenient API to translate technology specific exceptions  (thrown  by JDBC, Hibernate..etc.) in to consistent unchecked exceptions.
Aspect-Oriented Programming : AOP breaks program part in to distinct parts (called concerns). It's used to increase modularity by cross-cutting techniques.A cross cutting concern is a concern that can affect the whole application and should be centralized in one location in code as possible, such as transaction management , authentication, logging, security ..etc.

Spring Bean: 

Any normal Java class that is initialized by Spring IOC container is called Spring Bean. We use Spring application context to get Spring Bean instance. Spring IOC Container manages the lifecycle of Spring Bean Scope and injecting any required dependencies in the bean.

Different scopes of Spring bean:

When we declare <bean>, we can specify scope of the bean to inform the IOC container about the creation of the bean and how long it will survive.
For any Java application there are two different scopes called Singleton and Prototype.
There are three different scopes i.e. request, session and global-session specifically for Spring based Java web applications.
  • Singleton is the default scope of any bean. This means a single instance of the bean will get created per IOC Container. Hence the Singleton beans are not thread safe.
  • In Prototype scope a new instance will get created every time the bean is requested.
  • In request scope, a bean is defined to an HTTP request, This scope is valid only in a web-aware spring ApplicationContext.
  • In Session scope, a bean is defined to an HTTP session. This Scope is valid only in a web-aware Spring ApplicationContext.
  • In global-session scope, a bean is defined to a global HTTP session. This scope is valid only in a web-aware spring ApplicationContext.


To set the scope of the spring bean, we can use scope attribute in <bean> tag. @Scope is used in annotation based DI.


Spring IoC Container :

The Spring Container is at the core of the Spring framework. The container will create the objects, wire them together, configure them, and manage their complete life cycle from creation till descrution. The Spring container uses dependency injection(DI) to manage the componenets that make up an application.

There are two different types of applications:
  • BeanFactory Container : This is the heart of the Spring Container. org.springframework.beans.factory.BeanFactory is an interface and acts as a IoC Container which instantiates, Configures, and manages a number of beans.
  • ApplicationContext container: org.springframework.context.ApplicationContext interface also acts as the IoC Container but the ApplicationContext interfaceis builf on top of the BeanFactory interface to provides some extra functionality than BeanFactory such as simple integration with Spring's AOP, message resource handling (for l18N), event propogation application layer specific context (e.g. WebApplicationContext) for web application. So it is better to use ApplicationContext than BeanFactory.
For annotation based dependency injection, @Autowired annotation is used. The Classes marked with @Component /@Service / @Repository etc can be injected to the property which is marked with @Autowired

@Autowired is applied to 
  • field : for the filed-based dependency injection
  • setter for the setter dependency injection. Same as field-based dependency injection.
  • constructor for constructor-based dependency injection
Difference between constructor based and setter based DI : 
  • Injection of dependencies can be optional or mandatory. For Mandatory injection we use constructor based DI. While for the optional dependencies we can use setter based DI. However, we can mark a setter based DI with @Required annotation.
  • In case of cyclic dependency, constructor based DI won't be able to inject but setter based DI would be able to inject
  • If more number of parameters to be injected then it is advisable to use constructor based DI
Difference between context:annotation-config and context: component-scan:

context:annotation-config is used to activate annotations in beans already registered in the application context. context:component-scan can also do what context:annotation-config does but also scans packages to find and register beans within the application context.

Difference between @Component, @Controller, @Repository & @Service annotations

If a class is marked with @Component/@Controller/@Service/@Repository annotation then the spring DI container can identify the class during component scan mechanism. However, it is good idea to use @Service for service layer classes and @Controller should be used in spring MVC web controller.@Repository is used to import DAOs in to DI container. Also any unchecked exception will get translated into Spring DataAccessException.

ViewResolver vs MultipartResolver:

ViewResolver is used to resolve view by name. This interface is implemented by InternalResourceViewResolver MultipartResolver is used to handle file upload in web application.

Validation in Spring MVC:

org.springframework.validation.Validator interface supports spring MVC validation. Some of the util methods to validate a form are rejectIfEmptyOrWhitespace() and rejectIfEmpty() in the ValidationUtils class.

Example : 

@Component public class EmployeeValidator implements Validator { public boolean supports(Class clazz) { return EmployeeVO.class.isAssignableFrom(clazz); } public void validate(Object target, Errors errors) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "error.firstName", "First name is required."); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "error.lastName", "Last name is required."); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email", "Email is required."); } }


Another approach to validate form in Spring MVC is:
  • Use Hibernate Validations (Eg; @NotNull, @Size etc) for the properties of the model bean
  • Use @Valid, BindingResult in the method signature of the controller.
  • BindingResult.hasErrors() methods to validate the model bean.
Spring MVC interceptor:

HandleInterceptor interface acts as a spring MVC interceptor. It intercepts before and after serving the request. preHandle(), postHandle() and afterCompletion() are the methods to be overridden in case you implement HandlerInterceptor interface. However, to avoid overriding, you can use HandleInterceptorAdapter class.

Difference between Spring DAO and Spring ORM:

DAO is a design pattern to minimize coupling between the application and the backend ORM deals with how to map objects in to an object relation database which reduces coupling between the database and application.
If you use ORM without DAO then your application will become ORM dependent so it would be hard to move from One ORM (say hibernate ) to another ORM (e.g. NoSQL).

Spring DAO implemented using @Repository annotation. Spring repository extends JPARepository and passes JPA entity and its primary key.