2

In particular, I want to create a custom field for Task for a specific unit test, then delete that field when the test is finished.

I know Salesforce uses the Metadata API, but this seems designed to be used externally (via REST or SOAP web services).

I am also aware that there is a separate development, APEX Metadata API, that allows us to access said API via Apex (by making Web service calls!): https://github.com/financialforcedev/apex-mdapi

Is there a way of calling into the Metadata API natively? Or, to make the problem scope smaller, can I create/delete custom Task fields via APEX?

Thanks

Edit: there seems to be some confusion as to why I want to do this. Basically, I'm creating a managed package, which can be installed by different customers in their respective orgs. Each and every org will be customised in a different way, so I cannot make any assumption as to what these customisations will be.

What I want to test is how a certain part of my code that deals with tasks will behave in the presence of some custom fields. That is why I wanted to create a field, run my code, then delete the field, in the context of a unit test.

I considered the question answered, as 2 people have come back to me telling me that I cannot modify metadata from APEX.

3
  • 2
    I'm struggling to understand why you would need a field just for an Apex test. The purpose of Apex tests are to test Apex. Apex can't natively modify data model, so writing an Apex test to make something happen that Apex can't do in the first place seems unnecessary. Can you explain more why you want to do this, and perhaps there is a better way to do what you want to do.
    – pchittum
    Sep 30, 2014 at 9:37
  • Apex can't natively modify data model ... you just answered my question there. I work in the context of a managed package: we create a managed package, which our customers can install in their orgs. They can have custom fields, and we want to support them. I don't want to deploy the custom field as part of the package; instead, I want to simulate the fact that a customer might have a custom field in the context of my test.
    – mkorman
    Sep 30, 2014 at 14:01
  • Ok. I went ahead and answered with suggestions for how to accomplish this goal, and why Apex tests don't perform this job.
    – pchittum
    Oct 3, 2014 at 7:43

2 Answers 2

0

The Apex testing framework is built to test functionality implemented in Apex.

But there is a lot more functionality in an org than just Apex, so a natural extension of this test functionality is to want to begin to test other functionality. In some cases, the natural features of the Apex test framework align quite closely.

Take for example workflow actions like field updates and assigning tasks. Because these are both data-oriented features, you could easily test the functionality of those features.

But many features do not align with Apex test functionality, most especially configuration/metadata changes.

Furthermore, the testing framework works primarily in the context of the runtime transaction model and is designed to leave no footprint either inside of the org (ringfencing of real data, no commits to data changes, and automatic rollback of DML) and in systems that are integrated with the org (no callouts allowed).

I think the tests you propose are a very good idea. I just think you will need to use an external testing framework to do so. With greater and greater support of config changes in the metadata and tooling API, these kinds of processes are becoming easier to automate.

Perhaps you could adapt your existing build process to perform this test. In other words after you deploy to your sandbox/trialforce org, automate a follow on process to deploy some metadata changes and then rerun all tests.

2
  • I guess this sums it up quite nicely. We could create an action in our build server to deploy a mini-package containing only the custom field in question. The issue is that we're then tying our custom Apex tests with having deployed that mini-package previously.
    – mkorman
    Oct 3, 2014 at 12:35
  • Yeah. Or you push that test to the external testing framework. I'm working with a project right now that is doing just that. Tests make API calls into the org to test (in Ruby in this instance) that certain features are implemented according to spec. I didn't write the test harness, but essentially I'm writing tests that make calls to API endpoints, or sometimes execute anonymous Apex, that gets a result, then it is the ruby script that tests for pass/failure.
    – pchittum
    Oct 3, 2014 at 13:51
0

You can not modify metadata using test classes.

Metadata class invoke web-service so, to imitate the request and response you should use Mock classes. Basically, you are writing a test class for web-service.

Create a new Mock class and implement required response there using Test.setMock.

Ex: A sample test class:

@isTest

private class WebSvcCalloutTest {
    @isTest static void testEchoString() {              
        // This causes a fake response to be generated
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());

        // Call the method that invokes a callout
        String output = WebSvcCallout.callEchoString('Hello World!');

        // Verify that a fake result is returned
        System.assertEquals('Mock response', output); 
    }
}

A Sample Mock class to imitate the response:

@isTest

global class WebServiceMockImpl implements WebServiceMock {
   global void doInvoke(
           Object stub,
           Object request,
           Map<String, Object> response,
           String endpoint,
           String soapAction,
           String requestName,
           String responseNS,
           String responseName,
           String responseType) {
       docSample.EchoStringResponse_element respElement = 
           new docSample.EchoStringResponse_element();
       respElement.EchoStringResult = 'Mock response';
       response.put('response_x', respElement); 
   }
}

This way you can get required response in main class using during unit test run and your code can perform further. Reference: https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_callouts_wsdl2apex_testing.htm

Also, if there is situation where you are checking for deleted field in main class then you can use Test.isRunningTest()

1
  • Thanks for taking the time to answer this, but this is not what I want. I am not interested in testing a web service. I want to know how our code behaves in the presence of a custom field, and I wanted to create for this. The test would create a custom field for me, run the code under test, and then delete the field.
    – mkorman
    Oct 1, 2014 at 12:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .