Program flow

Under the hood Carina uses TestNG framework, so the first class to initialize is RemoteTestNGStarter.class. Program life cycle logic could be observed at TestNG.class run() method.

The initializing turn comes to Carina when CarinaListenerChain.class object created. It extends ListenerChain.class which will create, sort and attach AbstractTest.class listeners. This whole sequence is described in TestRunner.class init() method.

AbstractTest.class listeners are:

@LinkedListeners({ CarinaListener.class, TestRunListener.class, DataProviderInterceptor.class })

Theese listeners being attached and created when transform(IListenersAnnotation annotation, Class testClass) method is called.

  • TestRunListener.class and DataProviderInterceptor.class are implemented in zebrunner.

  • CarinaListener.class as it comes from the name is a Carina's listener.

Because CarinaListener object created, the class static field is initialized in it. There are several important steps inside:

  • R.reinit(). This method load's default values for all parameters from carina-core , then override's them with users configuration (api.properties, config.properties, testdata.properties, email.properties, report.properties, database.properties).
  • Configure log4j properties
  • Initializing L10N feature.

Then listeners attached to different Lists according to their implementations in TestNG:

Report link

After that methods are called in appropriate order in the ListenerChain.class:

  • onStart(ISuite suite). There is called every ISuiteListener's onStart() method that where mentioned in AbstractTest.class (CarinaListener and TestRunListener). CarinaListener.class onStart(ISuite suite) method will configure logging level and thread count.

  • now your test class is considered initialized and onStart(ITestContext testContext) method is called. Udid is generated there.

  • onBeforeClass(ITestClass testClass). Complete steps described in @BeforeClass annotation from your test.

  • onTestStart(ITestResult result) provide described data to test.

Next TestRunner.class runs code described in your test.class. The following route depends on what you are doing in your test:

UI (web, mobile)

@Test @MethodOwner()
public void webTest() {
   HomePage chromeHomePage = new HomePage(getDriver());
   chromeHomePage.open();
   Assert.assertTrue(chromeHomePage.isPageOpened(), "Chrome home page is not opened!"); 
} 

Debug entry point at : AbstractPage constructor and IDriverPool getDriver() method.

API

@Test()
public void testCreateUser() throws Exception {
   PostUserMethod api = new PostUserMethod();
   api.expectResponseStatus(HttpResponseStatusType.CREATED_201);
   api.callAPI();
   api.validateResponse();
}

Debug entry point at : AbstractApiMethodV2 constructor.

Database

@Test
public void createUser() {

   User USER = new User() {{
                     setUsername("bmarley");
                     setFirstName("Bob");
                     setLastName("Marley");
                     setStatus(Status.ACTIVE);
   }};

   try (SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession(true)) {
     UserMapper userMapper = session.getMapper(UserMapper.class);
     userMapper.create(USER);
     checkUser(userMapper.findById(USER.getId()));
   }
}

These are user's classes, samples at carina-demo: UserMapper, ConnectionFactory, User.