TestNG integration

To use Testify in TestNG, your tests will sit in an inheritance hierarchy with com.formos.tapestry.testify.testng.TapestryTest class as the root, your own AbstractMyApplicationTest as a common superclass and then the tests inheriting from that:

         TapestryTest
              ^
              |
  AbstractMyApplicationTest
     ^        ^         ^
     |        |         |
  MyTest1  MyTest2   MyTest3

The base class orchestrates a very particular sequence of calls that make the Testify functionality work; the abstract base class allows you to define common state and setup for all tests.

Common abstract base class

Your AbstractMyApplicationTest must create a TapestryTester and store it in a static variable so all the tests can share it. The code should look like this:

import com.formos.tapestry.testify.core.TapestryTester;
import com.formos.tapestry.testify.testng.TapestryTest;

public abstract class AbstractMyApplicationTest extends TapestryTest {
    private static final TapestryTester SHARED_TESTER =
        new TapestryTester("demo", MyCoreModule.class);

    public AbstractMyApplicationTest() {
        super(SHARED_TESTER);
    }    
}

If you have standard setup for all tests (such as using Mockito), then override setUpForAllTestMethods() by adding that method to your AbstractMyApplicationTest.

Test classes

In your test subclasses you'll need to override doSetUp() instead of using @BeforeMethod.

You will find your tests have access to a protected variable tester that provides access to the shared TapestryTester object. This object provides all the facilities of Tapestry's PageTester, plus a few more. For example:

import org.apache.tapestry5.dom.Document;

import com.formos.tapestry.testify.core.ForComponents;

public class MyTest1 extends AbstractMyApplicationTest {
    @ForComponents
    private FakeMyService myService;
    
    public doSetUp() {
        myService = new FakeMyService();
    }

    @Test    
    public void whenMyServiceReturnsAValueThenThePageIncudesThatVaue() {
        myService.setValue("Hello");
        Document document = tester.renderPage("MyPage");
        assertEquals("Hello", document.getElementById("value").getChildMarkup());
    }
}

Note that the @Inject annotations are processed at the start of each test class (@BeforeClass). If you want to do some processing @BeforeSuite then you'll need to manually force the annotation processing as the following example shows.

An alternative to doing setup with @BeforeSuite is to configure a fake or alternative IOC module that does the setup. You pass this module as a parameter when creating your TapestryTester (see integration testing).

public class BeforeSuiteTest extends AbstractMyApplicationTest {
    @Inject MyService myService;
            
    @BeforeSuite
    public void suiteSetup() {
        tester.injectInto(this);   // Cause @Inject to be processed on 'this' object
        myService.doSomething();
    }    
}