Skip to content

Class Repository

Dmytro Mykhaliev edited this page Aug 13, 2019 · 5 revisions

Prerequisite

From release 1.3.0, CodeSV provides functionality for defining class repositories containing predefined transactions. The main advantage of class repositories is the easy reuse of defined transactions between different tests and test classes in the same project. It also improves the combination of transactions and provides a single place to configure a set of transactions.

Basic Usage

The most simple way to define the class repository is to create a new class and create public methods with the @TransactionDefinition annotation and provide a unique name of the transaction. The uniqueness of the name is important as it is used for calling the defined transaction in test method.

Bodies of methods should define the virtualized services using common fluent API from CodeSV.

Class Repository:

public class DefaultRepository { 

  public static final String SERVICE_URL = "http://www.carepositories.com";

  /**
   * Demo method.
   */
  @TransactionDefinition(name = "simpleResponse")
  public void virtualizedSimpleDefaultResponse() { 
    ServiceResult result = new ServiceResult();
    result.setTxnName("simpleResponse");

    forGet(SERVICE_URL + "/simpleDefaultService").doReturn(
        okMessage().withJsonBody(new Gson().toJson(result))
    );
  }

  @TransactionDefinition(name = "commonResponse")
  public void commonResponse() {
    ServiceResult result = new ServiceResult();
    result.setTxnName("commonResponse");
  
    forGet(SERVICE_URL + "/commonService").doReturn(
        okMessage().withJsonBody(new Gson().toJson(result))
    ); 
  }
}

Once the class repository is created, it is required to declare a VirtualServerRule and provide information about it to the TxnRepoStore object using the @TransactionClassRepository annotation. This annotation has the required field repoClasses. This is a list of classes defining class repositories.

To be able to find the class repositories in the project, it is required to provide this object to the TxnRepoStore like this:

@TransactionClassRepository(repoClasses = {DefaultRepository.class})
public class ClassRepositoryExample {
 @Rule
 public VirtualServerRule vs = new VirtualServerRule();
 private TxnRepoStore store = new TxnRepoStoreBuilder().build(this);

After the VirtualServerRule and TxnRepoStore are successfully created and it is found the defined class repositories, we can use its object and method useTransaction(String txnName) to load the transactions from class repositories by the names provided in the @TransactionDefinitionannotation.

Full Test Class:

@TransactionClassRepository(repoClasses = {DefaultRepository.class})
public class ClassRepositoryExample {
@Rule
public VirtualServerRule vs = new VirtualServerRule();
private TxnRepoStore store = new TxnRepoStoreBuilder().build(this);
  @Test
  public void simpleMultipleCallTest() throws Exception { 
    String simpleTransactionName = "simpleResponse";
    String commonTransactionName = "commonResponse";
    store.useTransaction(simpleTransactionName);
    store.useTransaction(commonTransactionName);
    ServiceResult result = getResult("/simpleDefaultService");
    assertEquals(simpleTransactionName, result.getTxnName());
    result = getResult("/commonService");
    assertEquals(commonTransactionName, result.getTxnName());
  }
  private ServiceResult getResult(String path) throws IOException {
    HttpClient client = HttpClientBuilder.create().build();
    HttpGet request = new HttpGet(DefaultRepository.SERVICE_URL + path);
    HttpResponse response = client.execute(request);
    String responseBody = EntityUtils.toString(response.getEntity());
    return new Gson().fromJson(responseBody, ServiceResult.class); 
  }
}

Advanced usage

The previous example is a simple way to provide the most basic usage and does not provide a lot flexibility because we are calling the transactions by names only. To give more control and flexibility for calling transactions and combinations CodeSV provides additional optional parameters and functionality.

@VirtualServiceRepository

This annotation is optional for class repositories. This annotation provides additional control over repositories and you can give a unique name to the whole class repository. This helps in with the definition of multiple repositories with similar transactions that all share the same name in the repositories. For example, you can define QA and DEV repositories with the same transaction name but different virtualization.

@VirtualServiceRepository(serviceName = "QA service")
public class QaRepository {
}
Tags

To provide even more control over similar transaction definitions, it is possible to use tags in the @TransactionDefition annotation. Using combinations of virtual service name, transaction name and tags you can create complex logic for specific tests without duplication of logic in each test. The annotation has the optional parameter tags that is used for specifying the list of tags of the transaction.

@TransactionDefinition(name = "simpleResponse", tags = {"COMMON", "QA"})
public void virtualizedSimpleDefaultResponse() {
}

@TransactionDefinition(name = "anotherResponse", tags = "QA")
public void qaResponse() {
}
UseTransactionRule

To leverage additional information for class repositories and transactions, it is required to use a special object in your tests as the basic method useTransaction(String txnName) is not enough. For advance usage, CodeSV provides the UseTransactionRule object with fluent API for defining criteria for transactions. Afterwards the created object can be passed to the transaction store using the method store.useTransactionWithRule(UseTransactionRule rule) to load transactions matching the created criteria to the virtual server.

Defined rules use AND logic, so only transactions that match all defined criteria are loaded. Transaction name is an optional parameter and can be omitted if you want to load all transaction based on tags. If the transaction definition has more than one tag and you define a rule with just one tag that matches one of the tags in the list of tags then the transaction is loaded.

// Loads all "myTransaction" transactions that also contain tag "COMMON" and "QA"
UseTransactionRule rule = UseTransactionRule.RuleBuilder.crossServiceBuilder()
        .forTransaction("myTransaction")
        .withTag("COMMON")
        .withTag("QA")
        .build();
store.useTransactionWithRule(rule);
// Loads all transaction in repositories that contain "QA" tag
UseTransactionRule rule = new UseTransactionRule.RuleBuilder("QA service").withTag("QA").build();
store.useTransactionWithRule(rule);

For a complete example see: Repositories examples

Clone this wiki locally