blob: dae9b3a3c4e5f9bd9c4c8d1314a21b62266a56ee [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Apache TomEE</title>
<meta name="description"
content="Apache TomEE is a lightweight, yet powerful, JavaEE Application server with feature rich tooling." />
<meta name="keywords" content="tomee,asf,apache,javaee,jee,shade,embedded,test,junit,applicationcomposer,maven,arquillian" />
<meta name="author" content="Luka Cvetinovic for Codrops" />
<link rel="icon" href="../favicon.ico">
<link rel="icon" type="image/png" href="../favicon.png">
<meta name="msapplication-TileColor" content="#80287a">
<meta name="theme-color" content="#80287a">
<link rel="stylesheet" type="text/css" href="../css/normalize.css">
<link rel="stylesheet" type="text/css" href="../css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="../css/owl.css">
<link rel="stylesheet" type="text/css" href="../css/animate.css">
<link rel="stylesheet" type="text/css" href="../fonts/font-awesome-4.1.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="../fonts/eleganticons/et-icons.css">
<link rel="stylesheet" type="text/css" href="../css/jqtree.css">
<link rel="stylesheet" type="text/css" href="../css/idea.css">
<link rel="stylesheet" type="text/css" href="../css/cardio.css">
<script type="text/javascript">
<!-- Matomo -->
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = "//matomo.privacy.apache.org/";
_paq.push(['setTrackerUrl', u + 'matomo.php']);
_paq.push(['setSiteId', '5']);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.async = true;
g.src = u + 'matomo.js';
s.parentNode.insertBefore(g, s);
})();
<!-- End Matomo Code -->
</script>
</head>
<body>
<div class="preloader">
<img src="../img/loader.gif" alt="Preloader image">
</div>
<nav class="navbar">
<div class="container">
<div class="row"> <div class="col-md-12">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/" title="Apache TomEE">
<span>
<img
src="../img/apache_tomee-logo.svg"
onerror="this.src='../img/apache_tomee-logo.jpg'"
height="50"
>
</span>
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right main-nav">
<li><a href="../docs.html">Documentation</a></li>
<li><a href="../community/index.html">Community</a></li>
<li><a href="../security/security.html">Security</a></li>
<li><a class="btn btn-accent accent-orange no-shadow" href="../download.html">Downloads</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div></div>
</div>
<!-- /.container-fluid -->
</nav>
<div id="main-block" class="container main-block">
<div class="row title">
<div class="col-md-12">
<div class='page-header'>
<h1>Writing Validation Tests</h1>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="sect1">
<h2 id="_summary">Summary</h2>
<div class="sectionbody">
<div class="paragraph">
<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>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_validation_framework">The Validation Framework</h2>
<div class="sectionbody">
<div class="olist arabic">
<ol class="arabic">
<li>
<p><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</p>
</li>
</ol>
</div>
<div class="paragraph">
<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>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>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></p>
</li>
<li>
<p>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>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="ClassDiagram.png" alt="ClassDiagram">
</div>
</div>
<div class="paragraph">
<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></p>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>The above rules are then executed one by one</p>
</li>
<li>
<p>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>
</li>
</ol>
</div>
<div class="paragraph">
<p>Format for the different levels follows this spirit:</p>
</div>
<div class="olist loweralpha">
<ol class="loweralpha" type="a">
<li>
<p>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.</p>
</li>
<li>
<p>Intended to contain the issue expressed in 1 with only the essential details, should not line wrap if possible.
Be terse.</p>
</li>
<li>
<p>Teacher&#8217;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&#8217;t just point out what is wrong, also point out what is right.
Use several lines if needed.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Here is an <em>example validation message</em></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console"> # 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>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="6">
<li>
<p>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.</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_validation_test_framework">The Validation Test Framework</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The test framework is specifically written with the following goals in mind:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>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</p>
</li>
<li>
<p>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</p>
</li>
<li>
<p>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</p>
</li>
<li>
<p>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>
<div class="olist loweralpha">
<ol class="loweralpha" type="a">
<li>
<p>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</p>
</li>
<li>
<p>The test method</p>
</li>
<li>
<p>Can be given any name</p>
</li>
<li>
<p>Must be annotated with @Keys and CANNOT be annotated with @Test.
The rest of the JUnit annotations can be used</p>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>Following annotations are provided by the framework</p>
</li>
<li>
<p>@Keys : is a collection of zero or more @Key</p>
</li>
<li>
<p>@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.</p>
</li>
</ol>
</div>
</li>
</ol>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Be Careful 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
</td>
</tr>
</table>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>Once you have written the test and successfully run it, you now need to generate the report.
Simply invoke the following maven command</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">mvn test -Dtest=ValidationKeysAuditorTest -DconfluenceUsername=YourConfluenceUsername -DconfluencePassword=YourConfluencePassword</code></pre>
</div>
</div>
<div class="paragraph">
<p>The above command will create a complete test coverage report and post it to this location <a href="validation-keys-audit-report.html">Validation Keys Audit Report</a></p>
</div>
<div class="sect2">
<h3 id="_quick_facts_about_validationrunner_and_things_to_keep_in_mind_while_writing_tests">Quick facts about ValidationRunner and things to keep in mind while writing tests</h3>
<div class="paragraph">
<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:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>A test method needs to be annotated with <code>org.apache.openejb.config.rules.Keys</code> instead of the <code>org.junit.Test</code></p>
</li>
<li>
<p>Any usage of the @Test annotation will be ignored.</p>
</li>
<li>
<p>If the @Keys and @Test annotation are used together on a test method, then the TestCase will error out.</p>
</li>
<li>
<p>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>
</li>
<li>
<p>The runner will invoke the test method and use the Assembler and ConfigurationFactory to create the application.</p>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>If the keys listed in the @Keys annotation match the keys found in the ValidationFailureException, the test passes, else the test fails.</p>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>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.</p>
</li>
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="margin-bottom: 30px;"></div>
<footer>
<div class="container">
<div class="row">
<div class="col-sm-6 text-center-mobile">
<h3 class="white">Be simple. Be certified. Be Tomcat.</h3>
<h5 class="light regular light-white">"A good application in a good server"</h5>
<ul class="social-footer">
<li><a href="https://www.facebook.com/ApacheTomEE/"><i class="fa fa-facebook"></i></a></li>
<li><a href="https://twitter.com/apachetomee"><i class="fa fa-twitter"></i></a></li>
</ul>
<h5 class="light regular light-white">
<a href="../privacy-policy.html" class="white">Privacy Policy</a>
</h5>
</div>
<div class="col-sm-6 text-center-mobile">
<div class="row opening-hours">
<div class="col-sm-3 text-center-mobile">
<h5><a href="../latest/docs/" class="white">Documentation</a></h5>
<ul class="list-unstyled">
<li><a href="../latest/docs/admin/configuration/index.html" class="regular light-white">How to configure</a></li>
<li><a href="../latest/docs/admin/file-layout.html" class="regular light-white">Dir. Structure</a></li>
<li><a href="../latest/docs/developer/testing/index.html" class="regular light-white">Testing</a></li>
<li><a href="../latest/docs/admin/cluster/index.html" class="regular light-white">Clustering</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../latest/examples/" class="white">Examples</a></h5>
<ul class="list-unstyled">
<li><a href="../latest/examples/simple-cdi-interceptor.html" class="regular light-white">CDI Interceptor</a></li>
<li><a href="../latest/examples/rest-cdi.html" class="regular light-white">REST with CDI</a></li>
<li><a href="../latest/examples/ejb-examples.html" class="regular light-white">EJB</a></li>
<li><a href="../latest/examples/jsf-managedBean-and-ejb.html" class="regular light-white">JSF</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../community/index.html" class="white">Community</a></h5>
<ul class="list-unstyled">
<li><a href="../community/contributors.html" class="regular light-white">Contributors</a></li>
<li><a href="../community/social.html" class="regular light-white">Social</a></li>
<li><a href="../community/sources.html" class="regular light-white">Sources</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../security/index.html" class="white">Security</a></h5>
<ul class="list-unstyled">
<li><a href="https://apache.org/security" target="_blank" class="regular light-white">Apache Security</a></li>
<li><a href="https://apache.org/security/projects.html" target="_blank" class="regular light-white">Security Projects</a></li>
<li><a href="https://cve.mitre.org" target="_blank" class="regular light-white">CVE</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="row bottom-footer text-center-mobile">
<div class="col-sm-12 light-white">
<p>Copyright &copy; 1999-2022 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>
</div>
</div>
</div>
</footer>
<!-- Holder for mobile navigation -->
<div class="mobile-nav">
<ul>
<li><a hef="../latest/docs/admin/index.html">Administrators</a>
<li><a hef="../latest/docs/developer/index.html">Developers</a>
<li><a hef="../latest/docs/advanced/index.html">Advanced</a>
<li><a hef="../community/index.html">Community</a>
</ul>
<a href="#" class="close-link"><i class="arrow_up"></i></a>
</div>
<!-- Scripts -->
<script src="../js/jquery-1.11.1.min.js"></script>
<script src="../js/owl.carousel.min.js"></script>
<script src="../js/bootstrap.min.js"></script>
<script src="../js/wow.min.js"></script>
<script src="../js/typewriter.js"></script>
<script src="../js/jquery.onepagenav.js"></script>
<script src="../js/tree.jquery.js"></script>
<script src="../js/highlight.pack.js"></script>
<script src="../js/main.js"></script>
</body>
</html>