blob: 2769067e26e36a87bd3a960cd7a23d76a3c89851 [file] [log] [blame]
<!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>&nbsp;&raquo&nbsp;<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 &copy; 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>