Pages

Create your Selenium test reports with Ant

In the previous blog post I described how to JUnit test your Selenium tests. Once you have this set up, you can use Ant to run this tests and create a report about the results.

Since there are standard targets for JUnit and JUnitReport in Ant, the Ant file is pretty clean. We start with setting up our environment, including a clean target. The tool I use to display the XML on my blog makes it a bit messy, but you get the idea:












    
    
    
    
    
    



    

We set up the output directories, the reports will come in the reports directory. In the Lib directory, we put the selenium standalone jar file that is used to run the Selenium test in JUnit. As well as the JUnit jar to run the JUnit test itself.

After that there are two targets, prepare and compile:

    
     
    



    
    

In the prepare we set up the structure and create the directories that we need. In the compile we look for all the java sources in the src directory and compile them to the classes directory. Now all that is left is a target to run the JUnit and create the reports:

  
    
      
        
      
    
    
    
  
  
    
      
    
    
  

I choose not to split those two target, since I never want to run a test without creating the reports or vice versa. The JUnit runs all the tests that are in the classes dir, where the compile target puts his output, he runs the JUnit test using the classpath that is set up in the environment and puts this in the output directory.
After this the JUnitReport tasks picks up the reports from the output directory and creates a HTML structure off all the tests that are ran. This is how the index.html looks:

  
You see an overview of the tests, the failures and erros, all clickable to drill down for more information.
If you like you can browse through the packages & classes.

JUnit test your application with Selenium

We want to test our ADF application with Selenium. To get this working, we use the Selenium IDE (Firefox plugin) to record a session. You can export this recorded session to different formats, since we are mainly Java/ADF developers at our project, we choose to export to Java.

Because we build ADF applications with the JDeveloper IDE, this is the preferred IDE to build the JUnit test as well. In the Fusion WebApplication I created an extra Project called ‘SeleniumTest’.


To get it working, you need to have the JUnit extension, you can easily install this through the Help -> Check for update menu.
Next to that, you also need to add the selenium-server-standalone jar, to your project. You can download the latest version from the Selenium download page.

First we’re going to record a session with Selenium. Start your application, open it in firefox and open the Selenium plugin. After that click the record button.


Now just navigate to your application, in this example I got a form and a table, I click the next button two times navigating to the ‘Purchasing’ department. For this example we’ll keep the test clean and simple.


Stop the record session by clicking the record button again, you’ll see it has recorded the clicks.
If you want, you can replay it with the play button to check if it works.


Now export your file through the menu File -> Export -> Java / JUnit 4 / WebDriver.


Save this Java file in your SeleniumTest project, after this you need to rename your package in the java file. In this java class you see a few methods, we’ll focus on two off them for now, the setUp and testHr.

 @Before
  public void setUp() throws Exception {
    driver = new FirefoxDriver();
    baseUrl = "http://127.0.0.1:7101/";
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
  }

Here the Firefox driver is initiated and the baseUrl is set.

  @Test
  public void testHr() throws Exception {
    driver.get(baseUrl + "/SeleniumAntJenkins/faces/untitled1.jspx");
    driver.findElement(By.cssSelector("#b3 > a.xg7 > span.xgf")).click();
    driver.findElement(By.cssSelector("#b3 > a.xg7 > span.xgf")).click();
  }

The testHr method is the actual JUnit test that get launched after the setUp.
There is one bug in this generated class. As you can see the baseUrl ends on a slash and the first line in the testHr method adds a slash. I prefer to change the baseUrl and remove the last slash behind the portnumber.

Now your test is ready to run.
Just right click the java class and run (or debug, as you prefer).


You’ll see that a FireFox browser is launched (with the text WebDriver in the right bottom). It follows the steps in your test case and closes the browser again. After that you see the green positive result in the JUnit test runner.


That’s all it takes to set up a simple JUnit test that does a functional (screen) test with the help of Selenium in the JDeveloper IDE.

Use Coherence cache with WebCenter Portal

On our last WebCenter Portal project, we didn't configure Coherence as our caching mechanism, but we used the default caching mechanism for the content presenter. During the development phase, we didn't really have any problems, until we started with a load & stress test on our application.

During the load test we saw a lot of 500 Errors. In the application log files we noticed the following NullPointerException was logged, especially the caused by clause was interessting:
Caused By: java.lang.NullPointerException
at java.util.LinkedHashMap.get(LinkedHashMap.java:333)
at oracle.wcps.cache.internal.MapCache.get(MapCache.java:142)
at oracle.webcenter.content.integration.spi.ucm.UCMCacheHelper.getSecurityInfo(UCMCacheHelper.java:279)
at oracle.webcenter.content.integration.spi.ucm.SecurityInfoHelper.getCachedSecurityInfo(SecurityInfoHelper.java:122)
at oracle.webcenter.content.integration.spi.ucm.UCMBridge.checkSecurityLevelForNode(UCMBridge.java:2626)
at oracle.webcenter.content.integration.spi.ucm.UCMBridge.canAccessNode(UCMBridge.java:2591)
at oracle.webcenter.content.integration.spi.ucm.NodeOps.getNodeFromCache(NodeOps.java:700)
at oracle.webcenter.content.integration.spi.ucm.NodeOps.getUCMNodeWithId(NodeOps.java:1480)
at oracle.webcenter.content.integration.spi.ucm.NodeOps.getNodeWithId(NodeOps.java:153)
at sun.reflect.GeneratedMethodAccessor752.invoke(Unknown Source)

We were able to reproduce this behavior quiet easily, with a load test from 10 sessions for 2 hours. After contact with Oracle Support about this issue, we decided to build in the Coherence caching mechanism.

It's not that hard to implement this feature, for example see a blog by the a team about Coherence cache. 

Ever since we're using Coherence instead of the default caching mechanism for the content presenters, the issue hasn't occurred anymore.

Drag your panes outside JDeveloper in 12c

One of the first things I noticed about 12c is the movement of the panes from the view menu to the window menu. I sometimes get a bit too aggressive in closing a lot of the little panes. When I want to get them back later, I just use the View menu (Window menu from now on) to get them back.


However, I noticed another really great features in JDeveloper 12c. You can drag your panes outside of your JDeveloper in 12c. This can be helpful if for example you want a small log window showing on your other monitor, but not the whole JDeveloper.
Just like you normally move a pane around in JDeveloper, for example I like to have my properties on the bottom instead of on the right side, click the pane and drag the pane out of your JDeveloper window.


Besides this, you can also reorder you tabs in JDeveloper by simple drag & drop, just like you're used to in your browser.

Look into your JVM with VisualVM

If you want some more information about your JVM, for example your integrated WLS. There is a very easy tool to use, it’s called VisualVM. You can download it from visualvm.java.net. Extract the .zip file and run the \bin\visualvm.exe.

Once the application is started, on the left you can pick a running java container, for example under Local your WebLogic. If you want, you can add remote hosts as well:


Selecting one opens an overview:


Now if you click the monitor tab, you can get more info about CPU, memory, classes and threads. Below an example of a memory graph:

Don't persist UIComponent state, now with attributes!

In this blogpost I showed how to disable the persistence of a UIComponent, but it was needed to write Java code to check for the specific component and change. In this blog entry I will show a more generic way to do this, with the attribute tag.

On the showDetailItem we define an attribute with a name and value:

        
        
     

The Java code for the addComponentChange method in the PortalComposerChangeManager now looks like this:
  public void addComponentChange(FacesContext context, UIComponent component,
                                 ComponentChange change)
  {
    Map attrs = component.getAttributes();
    String value = (String) attrs.get(NON_PERSIST_STRING);

    if (value != null)
    {
      logger.fine("NonPersist attribute found, we don't persist!");
      return;
    }
    super.addComponentChange(context, component, change);
  }

I defined a static final NON_PERSIST_STRING with the value "nonPersist", like the name of the attribute. If the attribute is found, we don't persist the componentChange.
If you want a more specific approach, you can still check for a specific ComponentChange, in the case of this example, we still check if the ComponentChange matches the value in the attribute (disclosed):
  public void addComponentChange(FacesContext context, UIComponent component,
                                  ComponentChange change)
  {
    Map attrs = component.getAttributes();
    String value = (String) attrs.get(NON_PERSIST_STRING);

    if (value != null)
    {
      if (change instanceof AttributeComponentChange &&
          value.equals(((AttributeComponentChange) change).getAttributeName()))
      { //we check if the attribute value equals the change.
        logger.fine("{0} attribute found; {1} event on {2}, we don’t persist.", new Object[]
            { NON_PERSIST_STRING, value, component.getClass() });
        return;
      }
    }
    super.addComponentChange(context, component, change);
  }

This code can be expanded or changed to check for specific changes according to your needs.
I uploaded a new workspace here, so you can download and browse the source if you want to.

Support for multiple session timeouts


Our use case was that we needed to support different timeouts for different application roles. This because our internal users are using the same application as our external users. There is no default support for this behavior in ADF, but you can achieve this by using a PagePhaseListener.

In our production application we used different settings, but for this example I configured the following web.xml parameters:
 
    3
  
  
    oracle.adf.view.rich.sessionHandling.WARNING_BEFORE_TIMEOUT
    60
  
The session-timeout is set to 3 minutes and we want to show the default ADF warning popup 1 minute before the session expires. In case of a internal user login, the session-timeout parameter get overridden.
This is achieved by creating a PagePhaseListener:
public class PortalPhaseListener implements PagePhaseListener
{
  private static final int INTERNAL_TIMEOUT = 360;

  public void beforePhase(PagePhaseEvent pagePhaseEvent)
  {
    if (pagePhaseEvent.getPhaseId() == JSFLifecycle.JSF_RESTORE_VIEW_ID)
    {
      final ExternalContext ectx = FacesContext.getCurrentInstance().getExternalContext();
      final SecurityContext secCtx = ADFContext.getCurrent().getSecurityContext();     

      if (secCtx.isAuthenticated() && isInternalUser())
      {
        final HttpServletRequest httpServletRequest = (HttpServletRequest) ectx.getRequest();        
        httpServletRequest.getSession().setMaxInactiveInterval(INTERNAL_TIMEOUT);
      }
    }
  }
}
I decided to do this in the restore view phase, first we check if the user is logged on and if the user has the internal role. If both are true, we set the MaxInactiveInterval on the HttpSession.
Now the timeout becomes 6 minutes, meaning that after 5 minutes the default ADF popup will show, informing the user that the session will expire if no activity is shown within the next minute.

The result is a different session timeout for different user roles, you can do this for as many roles as you like, making your timeout settings more flexible.