Category Archives: Test

Test a method calling System.exit()

Today I was writing test for one of our command line tools, and I had this problem where the method dumping everything, which I really needed to be called since that’s the outcome I was checking, also called System.exit(). I had to find a way to test this anyway. I thought about using PowerMock and mocking system but that would have been complicated because I would have to find the exact class calling the System.exit(). So here is another solution to avoid the System.exit to exit (yes that’s possible I didn’t know about that either).

The secrets lays in the SecurityManager mechanism of Java, this class not only allows you to check permissions, but also to check exit event. Therefore you can throw an exception if you want to stop the exit. Here is the code:
Continue reading

Drag and drop external files with Selenium

Selenium does not allow dropping external files on an element. However it may be mandatory for your test if you want to cover every functionality. We will see how to make it work with Firefox 28+ and Chrome. I haven’t tested that on other browsers. We will see three work around:

  • Simulate a drop event without any file
  • Simulate a drop of a file from the file system (easy way but only for text file)
  • Simulate a drop of any file from the file system

Simulate a drop event without any file

This is a mostly a JavaScript workaround, the files and the drop event are created in JavaScript, that’s why the browser matters.

First a simple version where you don’t want file from your file system, this is enough in most situation:

public void dropFiles(List<String> names, WebElement target) throws IOException {
        
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    String inputId = "seleniumDragAndDropInput";
        
    // Create the FileList
    exec.executeScript(inputId + "_files = [];");
    for (String name: names) {
        exec.executeScript(inputId + "_files.push(new File([new Blob(['This is my content'], {type: 'text/plain'})], '" + name + "'));");
    }
        
    String targetId = target.getAttribute("id");
        
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
        
    // Add the item function the the FileList
    // Create the drop event and dispatch it on the target
    String initEventJS = inputId + "_files.item = function (i) {return this[i];};"
        + "var eve=document.createEvent(\"HTMLEvents\");"
        + "eve.initEvent(\"drop\", true, true);"
        + "eve.dataTransfer = {files:seleniumDragAndDropInput_files};"
        + "eve.preventDefault = function () {};"
        + "eve.type = \"drop\";"
        + "document.getElementById('" + targetId + "').dispatchEvent(eve);";
        
    exec.executeScript(initEventJS);

    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
        
}

The File creation works only with Firefox 28+, with earlier version it says “operation is unsecure”.

Simulate a drop of a file from the file system (easy way but only for text file)

And now an other example where we are using file from the machine running the Selenium tests. However be careful because it is not really smart and file’s content needs to be without special characters or it will break the JavaScript. You should escape the content if you need more advanced content. I didn’t because I usually using the first solution and code my content. This is enough in most situation where a bit of plain text or xml are enough for my tests.

public void dropFiles(List<File> files, WebElement target) throws IOException {
        
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    String inputId = "seleniumDragAndDropInput";
        
    // Create the FileList
    exec.executeScript(inputId + "_files = [];");
    for (File file : files) {
        exec.executeScript(inputId + "_files.push(new File([new Blob(['" + readFile(file) + "'], {type: '" + Files.probeContentType(file.toPath()) + "'})], '" + file.getName() + "'));");
    }
        
    String targetId = target.getAttribute("id");
        
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
        
    // Add the item function the the FileList
    // Create the drop event and dispatch it on the target
    String initEventJS = inputId + "_files.item = function (i) {return this[i];};"
        + "var eve=document.createEvent(\"HTMLEvents\");"
           + "eve.initEvent(\"drop\", true, true);"
        + "eve.dataTransfer = {files:seleniumDragAndDropInput_files};"
        + "eve.preventDefault = function () {};"
        + "eve.type = \"drop\";"
        + "document.getElementById('" + targetId + "').dispatchEvent(eve);";
        
    exec.executeScript(initEventJS);

    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
        
}

private String readFile( File file ) throws IOException {
    BufferedReader reader = new BufferedReader( new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    while( ( line = reader.readLine() ) != null ) {
        stringBuilder.append( line );
        stringBuilder.append( ls );
    }
    reader.close();
    return stringBuilder.toString();
}

Simulate a drop of any file from the file system

Here is a solution to actually drop any file from the file system. We have to use an input (type=file) and since we can not set its value via JavaScript (for security reason, or we could upload any file from our visitor 🙂 ), we need to set the value with Selenium with sendKeys. But in order for this to work, the input needs to be visible. That’s why I set the form with a position fixed. We need to delete it once done.

final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();

WebElement target = browseContainer.contentListGrid;

String targetId = target.getAttribute("id");

// Add an id if the target doesn't have one
if (targetId == null || targetId.isEmpty()) {
    targetId = "seleniumDragAndDropInput_target";
    exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
}

exec.executeScript(
        "var f=dojo.create('form', {id: 'seleniumDragAndDropInput_form', style: {position: 'fixed', left: 0, top: 0, width:'100px', height: '100px'}}, dojo.body());"
        + "dojo.create('input', { type: 'file', id: 'seleniumDragAndDropInput' }, f);");

WebElement input = BrowserDriver.getCurrentDriver().findElement(By.id("seleniumDragAndDropInput"));
input.sendKeys(path);

exec.executeScript(
        "var files=dojo.byId(\"seleniumDragAndDropInput\").files;"
        + "var eve=document.createEvent(\"HTMLEvents\");"
        + "eve.initEvent(\"drop\", true, true);"
        + "eve.dataTransfer = {files:files};"
        + "eve.type = \"drop\";document.getElementById('" + targetId + "').dispatchEvent(eve);");

exec.executeScript("dojo.destroy('seleniumDragAndDropInput_form');");

if (targetId == "seleniumDragAndDropInput_target") {
    exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
}

You may need to change a bit if you are not using dojo and replace the byId, create and destroy but I an sure you have that with your favorite javascript framework.

Simulate a drop of multiple files from the file system

With Chrome, you could use almost the same code that the previous one. The only thing to do is to set the input as ‘multiple’ and split paths with a \n.

public static void dropFile(String[] paths, WebElement target) {
    
    StringBuffer b = new StringBuffer();
    for (int i = 0; i < paths.length; i++) {
        File f = new File(paths[i]);
        if (!f.isFile()) {
            Assert.fail(paths[i] + " is not a valid file path.");
        }
        b.append(f.getAbsolutePath());
        if (i < paths.length - 1) {
            b.append("\n");
        }
    }
    
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    
    String targetId = target.getAttribute("id");
    
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
    
        exec.executeScript(
                "var f=dojo.create('form', {id: 'seleniumDragAndDropInput_form', style: {position: 'fixed', left: 0, top: 0, width:'100px', height: '100px'}}, dojo.body());"
                + "dojo.create('input', { type: 'file', id: 'seleniumDragAndDropInput', multiple: 'multiple' }, f);");
    
    
        WebElement input = BrowserDriver.getCurrentDriver().findElement(By.id("seleniumDragAndDropInput"));
        input.sendKeys(b.toString());
    
        exec.executeScript(
                "var files=dojo.byId(\"seleniumDragAndDropInput\").files;"
                + "var eve=document.createEvent(\"HTMLEvents\");"
                + "eve.initEvent(\"drop\", true, true);"
                + "eve.dataTransfer = {files:files};"
                + "eve.type = \"drop\";document.getElementById('" + targetId + "').dispatchEvent(eve);");
    
    exec.executeScript("dojo.destroy('seleniumDragAndDropInput_form');");
    
    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
    
    
}

However, it does not work with Firefox because it does not accept multiple files in one input separated by \n. That’s why we need to use several inputs and then gather files from all inputs in a FileList to be used in the event. Here is the code.

public static void dropFile(String[] paths, WebElement target) {
    
    for (int i = 0; i < paths.length; i++) {
        File f = new File(paths[i]);
        if (!f.isFile()) {
            Assert.fail(paths[i] + " is not a valid file path.");
        }
        paths[i] = f.getAbsolutePath();
    }
    
    
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    
    String targetId = target.getAttribute("id");
    
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
    
    // Using one input with multiple file separated by \n does not work with Firefox
    // We need to use several input
    StringBuffer createInputs = new StringBuffer();
    // Create form
    createInputs.append("var f=dojo.create('form', {id: 'seleniumDragAndDropInput_form', style: {position: 'fixed', left: 0, top: 0, width:'100px', height: '100px'}}, dojo.body());");
    // Create inputs
    for (int i = 0; i < paths.length; i++) {
        createInputs.append("dojo.create('input', { type: 'file', id: 'seleniumDragAndDropInput" + i + "'}, f);");
    }
    
    exec.executeScript(createInputs.toString());
    
    // Then set file for each input
    
    for (int i = 0; i < paths.length; i++) {
        WebElement input = BrowserDriver.getCurrentDriver().findElement(By.id("seleniumDragAndDropInput" + i));
        input.sendKeys(paths[i]);
    }
    
    // Write code to gather all inputs files in one array;
    StringBuffer gatherInputs = new StringBuffer();
    gatherInputs.append("var seleniumDragAndDropFiles = [];");
    // Need to add the item method to stick to FileList API
    gatherInputs.append("seleniumDragAndDropFiles.item = function (i) { return seleniumDragAndDropFiles[i]};");
    for (int i = 0; i < paths.length; i++) {
        gatherInputs.append("seleniumDragAndDropFiles.push(dojo.byId(\"seleniumDragAndDropInput" + i + "\").files[0]);");
    }
    
    // Init event with our file
    exec.executeScript(
            gatherInputs.toString()
            + "var eve=document.createEvent(\"HTMLEvents\");"
            + "eve.initEvent(\"drop\", true, true);"
            + "eve.dataTransfer = {files:seleniumDragAndDropFiles};"
            + "eve.type = \"drop\";document.getElementById('" + targetId + "').dispatchEvent(eve);");
    
    exec.executeScript("dojo.destroy('seleniumDragAndDropInput_form');");
    
    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
    
    
}

 

Java 7 enforces bytecode verification

I had some issues lately when migrating to Java 7. As you may know if you read this blog, I’ve been playing these past few weeks with test framework and more precisely PowerMock. I also had to mess with the bytecode a bit myself because some libraries from ICN have dependencies missing and can not be hot recompiled by PowerMock (rebuilding the byte code during Runtime).

Well what I did with the bytecode didn’t work with Java 7. After some researches, I discovered than the byte code verification has been enforced with Java 7, to avoid injection of malicious code via bytecode modification. This is good for production, but in test when we like to mess with bytecode to allow us some tricks, that’s not really helpful. Anyway after a while I discovered the option to disabled this bytecode verification. Of course I wouldn’t recommend using that in production, but it can be useful for test.

For IBM JDK, I didn’t find yet a way to fall back to the old verification engine, so for now I just disable it. Add this to your JVM arguments when running test.

-Xverify:none

For SUN JDK, there is an option to fall back to the old verification engine. Alternatively you can also disable the verification the same way that we do for IBM JDK. Here is the option:

-XX:-UseSplitVerifier

Continue reading

Get started with Selenium

Last post of a three posts series about testing, after Unit Testing and Integration Testing, let’s talk about UI testing.

Introduction

Selenium is a Browser driver, basically it does what you would do if you were manually testing, i.e. clicking, looking for elements, selecting, scrolling…, except it does it alone, and can do it for hours without a break, every night…

How it works is quite simple, you are targeting DOM elements (or node, or WebElement, or any name you would like to call them) with selectors, and then you can do various operations on those like a user would do: wait for them to be present, to be visible, to be clickable, click on them, drag and drop something, enter information in a text field, …

Keep in mind that Selenium does the same thing that you would do. So if an element is not visible on the page and you would scroll to catch it before clicking, you have to do the same with Selenium, or it will throw an exception saying the element is not clickable because it is out of the view, which makes sense.

This article is an introduction to Selenium, if you want more applied examples for ICN and Dojo, you can read this post, but I would recommend you to read this one first to get familiar with Selenium.

Get started with Selenium

Continue reading

Test your ICN plug-in’s UI with Selenium

Lately I’ve been writing about test, and to finish this series of post, after unit tests and integration tests, I would like to talk about UI test. UI is not easy to test, because it requires a lot of user interactions. This is really important though, because UI tests make sure the final result, i.e. what the user sees, is what we want him to see. And as we all know, users remember mostly the UI defects 🙂

Update: I actually wrote an introduction on how to use Selenium, this post is meant more to give example of uses of Selenium applied to ICN and indirectly Dojo.

Not long ago, to test web application, we were writing test cases and you or any other unlucky tester was validating all of them one by one, and it was taking ages. Thanks god, there is nowadays better solutions, meaning lazy automatic solution. I will introduce in this post how to use a Web Browser automation tool to test ICN and your plug-in. We will use Selenium, which I think is a great tool. This will be applied to ICN, you can find plenty of Selenium tutorials on the web anyway, We will see how to automate basic action, like login, logout, create a folder, a document, file a document, accept message dialog. Then it will be up to you to adapt all this to your plug-ins.

Here is a quick video to give you an idea of what can be done with Selenium and ICN.

Continue reading

Integration Tests on ICN

After my few posts on Unit Testing, I would like to introduce how to do Integration Testing on ICN. Integrations Testing means interaction with other systems. in our case, it means FileNet. However for the IT, we don’t want to rely on the ICN server, because it would require user interaction, and this is the purpose of the UI test (see this post for more information).

The purpose of the Integration Tests is to call every services we wrote in our plug-in, directly and check changes made to the FileNet repository or other repositories are what we expect them to be.
Continue reading

Make EclEmma test coverage work with PowerMock

EclEmma and Mockito do not work well together out-of-the-box. EclEmma report no coverage at all on test run with PowerMock runner. However there is a way to make it work together, using the PowerMock javaagent. To do this, don’t use the @RunWith(PowerMockRunner.class) annotation as you’re used to. Instead, use the standard JUnit Runner or your runner extending a JUnit one, and add this rule to all your test classes:

@Rule
public PowerMockRule rule = new PowerMockRule();

You will also need to add the 2 following jars to your classpath, as explained here:

  • powermock-module-javaagent
  • powermock-module-junit4-rule-agent

You can find then on the Maven repository: here and here.

Third step is to initialize the agent, add the following lines to all your test classes, or to you runner if you have one to add it only once:

static {
     PowerMockAgent.initializeIfNeeded();
 }

And finally last step: modify your launch configuration running your test to add the following option to the VM arguments:

-javaagent:libs/powermock-module-javaagent-1.6.0.jar

And you should be able to use the Coverage As for EclEmma and see you test coverage result!