|
design issue: msg#00181java.junit.user
Can somebody suggest on some issue of JUnit API usage or test case design? Sorry for a long appendix code. The essence is that I want to start some application once in VM session and run all my test methods afterwards. I could not find sufficient place to put my initial call ClientMain.main (null); First I tried setUp(), but it is called before every test method. Then I tried to implement TestListener to use startTest() method. It in turn was not obvious, and you can see the indirect tricks I had to use with run() method and result class, please suggest me easier way. But anyways it did not help as startTest() was also called before every test method (what is the difference?) Then I finally used static counters. Please suggest me proper solution. ------------------------------------------------------------ package com.imc.testutil; // log4j import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.Logger; // junit import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestResult; import junit.framework.AssertionFailedError; import junit.framework.TestListener; /** This is intended wrapper for all imc test cases. <p> Here we <ol> <li>configure logger from properties file <li>add TestListener <li>count test method calls <li>distinguish first test method call for child to put all settings called once per suite <li>do some dummy loggings of method calls </ol> </p> <p> We experience the following design difficulties, deriving either from JUnit API imperfection or our poor usage of the latter, namely: <ol> <li>It was not obvious how to add TestListener. Then we needed to overwrite run() method which does not seem proper way. <li>The listener being added, we discover startTest() method to have unexpected functionality. We need the place to put code called once per suite. Instead, startTest() is called before every testXXX() method just like setUp() Then what is the difference? Likewise we could use setUp(), statically counting calls and implement firstSetUp(). </ol> @since on 10 June 2002 @author Boris Garbuzov */ public class ImcTestCase extends TestCase // second listener after TestRunner in the JVM process implements TestListener { /* We can use log befoe or in first constructor. */ static { PropertyConfigurator.configure("log4j.properties"); } /** this flag is static because testrunner create new instance of * of this class for every testXXX method. This flag is needed to fire * method firstStartTest() only one time. This method is famous for operations * that needs only one time. Look at method run(TestResult ..) @deprecated. currentStartTestIndex is used instead */ //private static boolean isStartTestFirst = false; /** generalizes the idea of isStartTestFirst checked and incremented in startTest() and published in getCurrentStartTestIndex It is good to police the usage so that this variable could be only incremented, and not voluntarily reset. */ private static int currentStartTestIndex = 0; /** JUnit after TestRunner calls this constructor with name = testXxxx - the current test method */ public ImcTestCase (String name) { super(name); //createResult().addListener (this); // does not help getDefaultLogger().info("instance created with name = " + name); } /** Extension Test code calls this method for casual logging needs. This should not add much overhead. Logger does quick lookup by name. That is why we get rid of the field. */ protected Logger getDefaultLogger() { return Logger.getLogger (getName()); } /** * Overide * Runs the test case and collects the results in TestResult. * And adds this class as TestListener Is it the only way? May be "createResult().addListener (this)" whould suffice? */ public void run(TestResult result) { result.addListener(this); super.run (result); } /** implements startTest interface method children can add here call of original application to be tested For the child class it is desirable to call this super first in case of overwriting to prevent obuse. */ public void startTest(Test test) { getDefaultLogger().info("Start test " + getName()); currentStartTestIndex++; // moved from run() if(currentStartTestIndex == 1) { firstStartTest(); } } /** implements addFailure interface method */ public void addFailure(Test test, AssertionFailedError assertionFailedError) { getDefaultLogger().error( assertionFailedError.getMessage() ); } /** implements endTest interface method */ public void endTest(Test test) { getDefaultLogger().info("Finish test " + getName()); } /** implements TestLister Here we just log the fact of invokation and print the error. The children can overwrite it adding sensible stuff. */ public void addError(Test test, Throwable throwable) { getDefaultLogger().error(throwable.getMessage()); } /** @since June 2002 for children to override it calling original application once per suite The child should not necessarily call this super, but it does not hurt too. */ public void firstStartTest() { getDefaultLogger().info ("\r\n IncTestCase.firstStartTest() is called \r\n"); } /** publishes current index of test method running */ public int getCurrentStartTestIndex() { return currentStartTestIndex; } } ------------------------------------------------------- package com.imc.mymailloop.demo.boris2.test4; // jdk import javax.swing.JFrame; import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.InputEvent; import java.awt.Color; // junit import com.imc.testutil.TestChartView; import com.imc.testutil.ImcTestCase; import junit.framework.Test; // jemmy import org.netbeans.jemmy.operators.JDialogOperator; import org.netbeans.jemmy.operators.AbstractButtonOperator; import org.netbeans.jemmy.operators.JFrameOperator; import org.netbeans.jemmy.operators.JMenuBarOperator; // log4j import org.apache.log4j.Logger; // ours import com.imc.mymailloop.demo.boris2.ClientMain; /** */ public class AppTest extends ImcTestCase { // this is timeout betwean test operations private static int SHOW_TIMEOUT = 2000; /** defined first and then used in test methods */ private JFrameOperator jframeMain = null; /** Creates new AppTest */ public AppTest(String name) { super(name); } /** overrides JUnit's default called before every test method 2 times in our case */ public void setUp() throws Exception { // gets main frame jframeMain = new JFrameOperator("Try it"); } /** overwrites super's Put here call of initial app instead of RunTests */ public void firstStartTest() { super.firstStartTest(); // just for logging // otherwise we can put this to static area. ClientMain.main (null); } /** first test method <ol> <li>It finds Help|About menu, <li>Pusles it, <li>Finds About dialog <li>Finds OK button on it <li>Pushes it. <li>Does sofisticated logging on the way. </ol> */ public void testMenu() { // stuff } } __________________________________________________ Do You Yahoo!? Yahoo! - Official partner of 2002 FIFA World Cup http://fifaworldcup.yahoo.com
|
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | Re: Are tests code or comment (was: distinguishing between failures and errors), J. B. Rainsberger |
|---|---|
| Next by Date: | Re: design issue, kentlbeck |
| Previous by Thread: | RE: Re: distinguishing between failures and errors, Mark Meyers |
| Next by Thread: | Re: design issue, kentlbeck |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |