| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| |
| <meta charset="UTF-8"> |
| <title>Writing Validation Tests</title> |
| <meta name="description" content="Apache TomEE"> |
| <meta name="author" content="Apache TomEE"> |
| <meta name="google-translate-customization" content="f36a520c08f4c9-0a04e86a9c075ce9-g265f3196f697cf8f-10"> |
| <meta http-equiv="Pragma" content="no-cache"> |
| <meta http-equiv="Expires" content="0"> |
| <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0"> |
| |
| <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> |
| <!--[if lt IE 9]> |
| <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> |
| <![endif]--> |
| |
| <!-- Le styles --> |
| <link href="./../resources/css/bootstrap.css" rel="stylesheet"> |
| <link href="./../resources/css/prettify.css" rel="stylesheet"> |
| <!--link href="./../resources/css/bootstrap-mods.css" rel="stylesheet"--> |
| <link href="./../resources/css/main.css" rel="stylesheet"> |
| <link href="./../resources/font-awesome-4.6.3/css/font-awesome.min.css" rel="stylesheet"> |
| |
| <script type="text/javascript"> |
| var t = encodeURIComponent(document.title.replace(/^\s+|\s+$/g,"")); |
| var u = encodeURIComponent(""+document.URL); |
| |
| function fbshare () { |
| window.open( |
| "http://www.facebook.com/sharer/sharer.php?u="+u, |
| 'Share on Facebook', |
| 'width=640,height=426'); |
| }; |
| function gpshare () { |
| window.open( |
| "https://plus.google.com/share?url="+u, |
| 'Share on Google+', |
| 'width=584,height=385'); |
| }; |
| function twshare () { |
| window.open( |
| "https://twitter.com/intent/tweet?url="+u+"&text="+t, |
| 'Share on Twitter', |
| 'width=800,height=526'); |
| }; |
| function pinshare () { |
| window.open("//www.pinterest.com/pin/create/button/?url="+u+"&media=http%3A%2F%2Ftomee.apache.org%2Fresources%2Fimages%2Ffeather-logo.png&description="+t, |
| 'Share on Pinterest', |
| 'width=800,height=526'); |
| }; |
| </script> |
| |
| <!-- Le fav and touch icons --> |
| <link rel="shortcut icon" href="./../favicon.ico"> |
| <link rel="apple-touch-icon" href="./../resources/images/apple-touch-icon.png"> |
| <link rel="apple-touch-icon" sizes="72x72" href="./../resources/images/apple-touch-icon-72x72.png"> |
| <link rel="apple-touch-icon" sizes="114x114" href="./../resources/images/apple-touch-icon-114x114.png"> |
| |
| <script src="./../resources/js/prettify.js" type="text/javascript"></script> |
| <script src="./../resources/js/jquery-latest.js"></script> |
| <script src="http://platform.twitter.com/widgets.js" type="text/javascript"></script> |
| <script src="./../resources/js/common.js"></script> |
| <script src="./../resources/js/prettyprint.js"></script> |
| <!--script src="//assets.pinterest.com/js/pinit.js" type="text/javascript" async></script//--> |
| |
| <script type="text/javascript"> |
| |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-2717626-1']); |
| _gaq.push(['_setDomainName', 'apache.org']); |
| _gaq.push(['_trackPageview']); |
| |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| |
| </script> |
| </head> |
| |
| <body> |
| |
| <div class="topbar" data-dropdown="dropdown"> |
| <div class="fill"> |
| <div class="container"> |
| <a class="brand" href="./../index.html">Apache TomEE</a> |
| <ul class="nav"> |
| <li class="dropdown"> |
| <a class="dropdown-toggle" data-toggle="dropdown" href="#"> |
| Apache |
| <b class="caret"></b> |
| </a> |
| <ul class="dropdown-menu"> |
| <!-- <li><a href="./../misc/whoweare.html">Who we are?</a></li> --> |
| <!-- <li><a href="./../misc/heritage.html">Heritage</a></li> --> |
| <li><a href="http://www.apache.org">Apache Home</a></li> |
| <!-- <li><a href="./../misc/resources.html">Resources</a></li> --> |
| <li><a href="./../misc/contact.html">Contact</a></li> |
| <li><a href="./../misc/legal.html">Legal</a></li> |
| <li><a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li> |
| <li><a href="http://www.apache.org/foundation/thanks.html">Thanks</a></li> |
| <li class="divider"/> |
| <li><a href="http://www.apache.org/security">Security</a></li> |
| </ul> |
| </li> |
| <li><a href="./../index.html">Home</a></li> |
| <li><a href="./../downloads.html">Downloads</a></li> |
| <li><a href="./../documentation.html">Documentation</a></li> |
| <li><a href="./../examples-trunk/index.html">Examples</a></li> |
| <li><a href="./../support.html">Support</a></li> |
| <li><a href="./../contribute.html">Contribute</a></li> |
| <li><a href="./../security/index.html">Security</a></li> |
| </ul> |
| |
| <!-- Google CSE Search Box Begins --> |
| <FORM class="pull-right" id="searchbox_010475492895890475512:_t4iqjrgx90" action="http://www.google.com/cse"> |
| <INPUT type="hidden" name="cx" value="010475492895890475512:_t4iqjrgx90"> |
| <INPUT type="hidden" name="cof" value="FORID:0"> |
| <INPUT size="18" width="130" style="width:130px" name="q" type="text" placeholder="Search"> |
| </FORM> |
| <!--<SCRIPT type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_010475492895890475512:_t4iqjrgx90"></SCRIPT>--> |
| <!-- Google CSE Search Box Ends --> |
| </div> |
| </div> |
| </div> |
| |
| <div class="container"> |
| |
| |
| <div class="page-header"> |
| <small><a href="./../index.html">Home</a> » <a href="./../dev/">Dev</a></small><br> |
| <h1>Writing Validation Tests |
| |
| <div style="float: right; position: relative; bottom: -10px; "> |
| <a onclick="javascript:gpshare()" class="gp-share sprite" title="Share on Google+">share [gp]</a> |
| <a onclick="javascript:fbshare()" class="fb-share sprite" title="Share on Facebook">share [fb]</a> |
| <a onclick="javascript:twshare()" class="tw-share sprite" title="Share on Twitter">share [tw]</a> |
| <a onclick="javascript:pinshare()" class="pin-share sprite" title="Share on Pinterest">share [pin]</a> |
| <a data-toggle="modal" href="#edit" class="edit-page" title="Contribute to this Page">contribute</a> |
| </div> |
| </h1> |
| </div> |
| |
| <p><a name="WritingValidationTests-Summary"></a></p> |
| |
| <h2>Summary</h2> |
| |
| <p>Validation is a critical and integral part of the project. If you are |
| writing some code which validates some rules, you should definitely write a |
| test for it. A little validation test framework is available to write tests |
| specifically for Validation. This page explains the details of writing such |
| tests using example snippets.</p> |
| |
| <p><a name="WritingValidationTests-TheValidationFramework"></a></p> |
| |
| <h2>The Validation Framework</h2> |
| |
| <ol> |
| <li><code>org.apache.openejb.config.ConfigurationFactory</code> uses a chain of |
| <code>org.apache.openejb.config.DynamicDeployer</code> implementations. One of the |
| implementations in the chain is |
| <code>org.apache.openejb.config.ValidateModules</code>. <code>ValidateModules</code> is |
| conditionally added to the <em>chain</em> if the property |
| <code>openejb.validation.skip=true|false</code>. If this property is false, then |
| <code>ValidateModules</code> is used to kick off the Validation Framework</li> |
| </ol> |
| |
| <p><a href="https://github.com/apache/openejb/tree/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java">Configuration Factory</a></p> |
| |
| <ol> |
| <li>Internally ValidateModules uses the <a href="https://github.com/apache/openejb/tree/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ValidateModules.java"><em>AppValidator.validate()</em> method</a></li> |
| <li>This method then performs validation using a number of rules. _A |
| validation rule/s is represented by a class implementing ValidationRule. |
| In fact, all the classes checking the validation rules , extend |
| ValidationBase, which further implements ValidationRule.</p> |
| |
| <p><img src="../images/ClassDiagram.png" alt="" align="center"></li> |
| </ol> |
| |
| <p>The <em>list of rules</em> being executed can actually be found in the following |
| method of <a href="https://github.com/apache/openejb/tree/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppValidator.java">AppValidator</a> |
| 1. The above rules are then executed one by one</p> |
| |
| <ol> |
| <li>Each module has an attached ValidationContext , which maintains a list of |
| failures, warnings and errors. As the above rules are being invoked, the |
| failure/errors/warnings for a module are being added to its |
| ValidationContext. Every Validation failure has an associated message which |
| can be found in <code>org/apache/openejb/config/rules/messages.properties</code>. A |
| message has three levels as explained below:</p> |
| |
| <p>Format for the different levels follows this spirit:</p> |
| |
| <ol> |
| <li>Should be short and fixed such that someone could search/grep for it |
| without having to know/use regular expressions. These tend to be similar |
| to the message key.</li> |
| <li>Intended to contain the issue expressed in 1 with only the essential |
| details, should not line wrap if possible. Be terse.</li> |
| <li>Teacher's assistant. A much more conversational and possibly more |
| detailed |
| explanation of the issue, should tell the user what to do to fix the |
| problem. |
| I.e. don't just point out what is wrong, also point out what is right. Use |
| several lines if needed.</li> |
| </ol></li> |
| </ol> |
| |
| <p>Here is an <em>example validation message</em></p> |
| |
| <pre><code># 0 - method name |
| # 1 - full method |
| # 2 - remote|home |
| # 3 - interface name |
| # 4 - EJB Class name |
| 1.no.busines.method No such business method |
| 2.no.busines.method Business method {0} not implemented. |
| 3.no.busines.method Business method {1} not implemented. The method was declared in the {2} interface {3}, but not implemented in the ejb class {4} |
| </code></pre> |
| |
| <ol> |
| <li>The validation framework does not stop processing on the first validation |
| failure, but keeps going and checking for other validation errors and |
| reports them all to the user. This allows the user to fix all errors in one |
| go and re-attempt deploying the application.</li> |
| </ol> |
| |
| <p><a name="WritingValidationTests-TheValidationTestFramework"></a></p> |
| |
| <h2>The Validation Test Framework</h2> |
| |
| <ol> |
| <li>The test framework is specifically written with the following goals in |
| mind:</li> |
| <li>It should be easy to write the test, and the framework should do |
| the boiler-plate work, the test author just needs to provide the relevant |
| info</li> |
| <li>It should report the test coverage i.e. the framework should |
| generate a report regarding which keys in messages.properties have tests |
| written for them and what is the corresponding Test class/es which test for |
| the validation rule associated with that key</li> |
| <li>It should ensure that if a test is being written for a specific |
| message key, then that key should exist in the messages.properties file</li> |
| <li>Lets break down the framework by using an <a href="https://github.com/apache/openejb/tree/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/rules/CheckInjectionTargetsTest.java">example</a></p> |
| |
| <ol> |
| <li>The first thing to note is that we are running the test using our |
| own custom runner i.e. <code>@RunWith(ValidationRunner.class)</code>. This runner |
| ensures that the keys we are testing, actually exist in the |
| messages.properties file. It does a lot more, as we shall see later </li> |
| <li>The test method</li> |
| <li>Can be given any name</li> |
| <li>Must be annotated with @Keys and CANNOT be annotated with @Test. |
| The rest of the JUnit annotations can be used</li> |
| <li>Must return one of EjbJar / EjbModule / AppModule. The returned |
| EjbJar/EjbModule/AppModule will be specifically created to cause one or |
| more validation errors/warnings/failures.</li> |
| <li>Following annotations are provided by the framework</li> |
| <li>@Keys : is a collection of zero or more @Key</li> |
| <li>@Key : represents a key for which this test is being written. A @Key |
| can be of type FAILURE or WARNING or ERROR. Default value is FAILURE. As |
| seen in the example above, the test() method is expecting two warnings for |
| the key injectionTarget.nameContainsSet. If count is not equal to 2 or some |
| other Validation Failure/Warning/Error was also thrown from the method, |
| then the test fails. |
| <h3>Be Careful</h3></li> |
| </ol></li> |
| </ol> |
| |
| <p>The test must cause a Validation Failure otherwise the test framework does |
| not get invoked. For example, in the above code, a Key of type WARNING is |
| being tested, however the test is purposely being failed by putting an |
| <code>@AroundInvoke</code> around the method with zero arguments</p> |
| |
| <ol> |
| <li>Once you have written the test and successfully run it, you now need to |
| generate the report. Simply invoke the following maven command</p> |
| |
| <p>mvn test -Dtest=ValidationKeysAuditorTest |
| -DconfluenceUsername=YourConfluenceUsername |
| -DconfluencePassword=YourConfluencePassword</li> |
| </ol> |
| |
| <p>The above command will create a complete test coverage report and post it |
| to this location <a href="openejb:validation-keys-audit-report.html">OPENEJB:Validation Keys Audit Report</a></p> |
| |
| <h3>Quick facts about ValidationRunner and things to keep in mind while writing tests</h3> |
| |
| <p>This class is created specifically to write tests which test OpenEjb |
| validation code. Specifically, it is used to check the usage of keys |
| defined in <code>org.apache.openejb.config.rules.Messages.properties</code>. To use this |
| runner, simply annotate your test case with |
| <code>@RunWith(ValidationRunner.class</code>). Here are some things to keep in mind when writing tests: <br /> |
| 1. A test method needs to be annotated with <br /> |
| <code>org.apache.openejb.config.rules.Keys</code> instead of the <code>org.junit.Test</code> <br /> |
| 2. Any usage of the @Test annotation will be ignored <br /> |
| 3. If the @Keys and @Test annotation are used together on a test method, |
| then the TestCase will error out <br /> |
| 4. Every test method should create a EjbJar or EjbModule or AppModule and |
| return it from the method. It should list the keys being tested in the |
| @Keys annotation</p> |
| |
| <ol> |
| <li>The runner will invoke the test method and use the Assembler and |
| ConfigurationFactory to create the application |
| 1.This will kick off validation and this Runner will catch |
| ValidationFailureException and make sure that all the keys specified in the |
| @Keys annotation show up |
| in the ValidationFailureException</li> |
| <li>If the keys listed in the @Keys annotation match the keys found in the |
| ValidationFailureException, the test passes, else the test fails.</li> |
| <li>This Runner also validates that the keys specified in the @Keys |
| annotation are also available in the |
| org.apache.openejb.config.rules.Messages.properties file. If the key is not |
| found, then the Runner throws and exception resulting in your test case not |
| being allowed to run.</li> |
| <li>Sometimes you want to write a test where you do not want any |
| ValidationFailureException to be thrown, in those scenarios, simply |
| annotate your test with @Keys and do not specify any @Key in it</li> |
| </ol> |
| |
| |
| |
| |
| <div id="edit" class="modal hide fade in" style="display: none; "> |
| <div class="modal-header"> |
| <a class="close" data-dismiss="modal">x</a> |
| |
| <h3>Thank you for contributing to the documentation!</h3> |
| </div> |
| <div class="modal-body"> |
| <h4>Any help with the documentation is greatly appreciated.</h4> |
| <p>All edits are reviewed before going live, so feel free to do much more than fix typos or links. If you see a page that could benefit from an entire rewrite, we'd be thrilled to review it. Don't be surprised if we like it so much we ask you for help with other pages :)</p> |
| <small>NOTICE: unless indicated otherwise on the pages in question, all editable content available from apache.org is presumed to be licensed under the Apache License (AL) version 2.0 and hence all submissions to apache.org treated as formal Contributions under the license terms.</small> |
| <!--[if gt IE 6]> |
| <h4>Internet Explorer Users</h4> |
| <p>If you are not an Apache committer, click the Yes link and enter a <i>anonymous</i> for the username and leave the password empty</p> |
| <![endif]--> |
| |
| </div> |
| <div class="modal-footer"> |
| Do you have an Apache ID? |
| <a href="javascript:void(location.href='https://cms.apache.org/redirect?uri='+escape(location.href))" class="btn">Yes</a> |
| <a href="javascript:void(location.href='https://anonymous:@cms.apache.org/redirect?uri='+escape(location.href))" class="btn">No</a> |
| </div> |
| </div> |
| <script src="./../resources/js/bootstrap-modal.js"></script> |
| |
| <footer> |
| <p>Copyright © 1999-2016 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. |
| Apache TomEE, TomEE, Apache, the Apache feather logo, and the Apache TomEE project logo are trademarks of The Apache Software Foundation. |
| All other marks mentioned may be trademarks or registered trademarks of their respective owners.</p> |
| </footer> |
| |
| </div> <!-- /container --> |
| |
| <!-- Javascript |
| ================================================== --> |
| <!-- Placed at the end of the document so the pages load faster --> |
| <script src="./../resources/js/bootstrap-dropdown.js"></script> |
| |
| </body> |
| </html> |