Ant Migration tool – sf:compileAndTest

I would like to configure the ant migration tool so that only test classes are run that we own so no managed package classes. Now i searched on the documentation of the tool and i only find the runAllTests = true, which runs all tests including managed package code.

then i found 2 other posts that are talking about the sf:compileAndTest method in ant where you can specify <runtests namespace="Default"/> but this doesn’t seem to work either.
there is a post here Get Status Updates When Running Tests with ANT Migration Tool

and here How to run tests in the default namespace in a sandbox using Ant

but both don’t really answer the question if the <runTests namespace="Default"/> actually works in ant or not.

does this work?

UPDATE:

I checked further the runAllTests=True and seems to run all test classes also the ones from a managed package. I tried with the sample build.xml and the latest Migration toolkit.

<target name="deployCodeCheckOnly">
  <sf:deploy username="username@username.be.full" password="password" serverurl="https://test.salesforce.com" maxPoll="500" deployRoot="codepkg" runAllTests="true" checkOnly="true"/>
</target>

As outcome of this run it gives me these test class failures which are from managed packages like CRMFusion’s DupeBlocker and others

[sf:deploy] Test Failures:
[sf:deploy] 198.  CRMfusionDBR101.DB_UnitTests.testRebuildKeys_MultipleLeads_MultiBatch_SameHash_DupeFirstBatch -- System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Please enter valid country 

[sf:deploy] Request Status: InProgress (487/689)  -- Running Test: DB_UnitTests.test_DB_KeyBuilder_useBatchApexKeyBuilder
[sf:deploy] Request Status: InProgress (493/689)  -- Running Test: DB_UnitTests.test_Db2Upgrade
[sf:deploy] Request Status: InProgress (500/689)  -- Running Test: DB_UnitTests.test_PostInstall

Answer

Edit: Summer ’15 made this “all better”. If you upgrade your ant-salesforce.jar to one that supports API version 34, you can now pass a “testLevel=RunLocalTests” attribute to sf:deploy like so:

<sf:deploy
  testLevel="RunLocalTests" 
  username="${sf.username}" 
  password="${sf.password}" 
  serverUrl="${sf.server}" 
  deployRoot="src" 
  />

From the docs:

http://releasenotes.docs.salesforce.com/en-us/summer15/release-notes/rn_deployment_run_subset_of_tests.htm

As part of this change, the runAllTests deployment option is now replaced with testLevel. You can choose which tests to run in a deployment by setting the desired test level. For a description of all test levels, see test levels for the deploy() call. In particular, to run a subset of tests in a deployment, set testLevel to the RunSpecifiedTests value and specify the tests to run in the runTests option.

And

http://releasenotes.docs.salesforce.com/en-us/summer15/release-notes/rn_api_meta_new_calls.htm#testlevels

RunLocalTests—All tests in your organization are run, except the ones that originate from installed managed packages. This test level is the default for production deployments that include Apex classes or triggers.

This was the workaround for pre-Summer ’15 for posterity:

Because I killed off the better part of a day hacking around in ant to accomplish the workaround @pepefloyd suggested, I wanted to publish a working example; In my case, the test classes are prefixed with “Test_” but you can fool around with the fileset as necessary

This is tested against v30 of the Force.com ant migration tool

<target name="test">
    <sfCompileAndTestUnmanaged checkOnly="true" username="${sf.username}" password="${sf.password}" server="${sf.server}">
        <fileset dir="src/classes">
            <include name="**/Test_*.cls"/>
        </fileset>
    </sfCompileAndTestUnmanaged>
</target>

<scriptdef name="sfCompileAndTestUnmanaged" language="javascript">
    <attribute name="checkonly"/>
    <attribute name="username"/>
    <attribute name="password"/>
    <attribute name="server"/>
    <attribute name="trace"/>
    <element name="fileset" type="fileset"/>

    <![CDATA[
        var filesets = elements.get("fileset");
        var filesetsIterator = filesets.iterator();
        var projectClasses = [];
        while(filesetsIterator.hasNext()){
            var fs = filesetsIterator.next();
            var iter = fs.iterator();
            while(iter.hasNext()){
                var resource = iter.next();
                var clazz = resource.getName().replace(".cls","");
                self.log("CLASS: " + clazz);
                projectClasses.push(clazz);
            }
        }

        var task = project.createTask("antlib:com.salesforce:compileAndTest");
        task.setCheckonly(attributes.get("checkonly") == 'true');
        task.setUsername(attributes.get("username"));
        task.setPassword(attributes.get("password"));
        task.setServer(attributes.get("server"));
        task.setTrace(attributes.get("trace") == 'true');

        //I tried 'importPackage' and conventional instantiation but couldn't get the inner class to instantiate; this works though
        var testsElement = task.getClass().getClassLoader().loadClass("com.salesforce.ant.CompileAndTest$RunTestsElement").newInstance();
        task.addRunTests(testsElement);

        var classClazz = task.getClass().getClassLoader().loadClass("com.salesforce.ant.CompileAndTest$CodeNameElement");
        for(i in projectClasses){
            var clazz = classClazz.newInstance();
            clazz.addText(projectClasses[i]);
            testsElement.addClass(clazz);
        }

        task.execute();
     ]]>
</scriptdef>

Alternatively, we’ve actually used a version of ‘deploy’ that does a no-op deploy (the package.xml in the ‘ant’ directory is empty except for the <version> element. This gives us incremental updates as the tests are running and allows the deployment of the source files to succeed in a separate ant target (not described below) while the tests may fail (insufficient code coverage, failing assertions, etc.)

<target name="test">
    <sfDeployUnmanaged purgeOnDelete="true" ignoreWarnings="true" username="${sf.username}" password="${sf.password}" serverUrl="${sf.server}" deployRoot="ant" maxPoll="75">
        <fileset dir="src/classes">
            <include name="**/*.cls"/>
        </fileset>
    </sfDeployUnmanaged>
</target>

<scriptdef name="sfDeployUnmanaged" language="javascript">
    <attribute name="purgeondelete"/>
    <attribute name="ignorewarnings"/>
    <attribute name="username"/>
    <attribute name="password"/>
    <attribute name="serverurl"/>
    <attribute name="deployroot"/>
    <attribute name="maxpoll"/>
    <attribute name="trace"/>
    <element name="fileset" type="fileset"/>

    <![CDATA[
        var filesets = elements.get("fileset");
        var filesetsIterator = filesets.iterator();
        var projectClasses = [];
        while(filesetsIterator.hasNext()){
            var fs = filesetsIterator.next();
            var iter = fs.iterator();
            while(iter.hasNext()){
                var resource = iter.next();
                var clazz = resource.getName().replace(".cls","");
                self.log("CLASS: " + clazz);
                projectClasses.push(clazz);
            }
        }

        var task = project.createTask("antlib:com.salesforce:deploy");
        task.setPurgeOnDelete(attributes.get("purgeondelete") == 'true');
        task.setIgnoreWarnings(attributes.get("ignorewarnings") == 'true');
        task.setUsername(attributes.get("username"));
        task.setPassword(attributes.get("password"));
        task.setServerURL(attributes.get("serverurl"));
        task.setDeployRoot(attributes.get("deployroot"));
        task.setMaxPoll(attributes.get("maxpoll"));
        task.setTrace(attributes.get("trace") == 'true');

        //Blows up when build timeout is reached if we don't set this (it uses this value when formatting the exception it throws)
        task.setOwningTarget(self.owningTarget);

        var classClazz = task.getClass().getClassLoader().loadClass("com.salesforce.ant.DeployTask$CodeNameElement");
        for(i in projectClasses){
            var clazz = classClazz.newInstance();
            clazz.addText(projectClasses[i]);
            task.addRunTest(clazz);
        }

        task.execute();
     ]]>
</scriptdef>

Attribution
Source : Link , Question Author : Sven Delporte , Answer Author : dav_i

Leave a Comment