<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>blog.smart-java.nl &#187; Testing</title>
	<atom:link href="http://blog.smart-java.nl/blog/index.php/category/testing/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.smart-java.nl/blog</link>
	<description>Ordina J-Technologies - Java Blog</description>
	<lastBuildDate>Wed, 05 May 2010 20:06:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Unit Testing a Bean Validation ConstraintValidator</title>
		<link>http://blog.smart-java.nl/blog/index.php/2010/03/12/unit-testing-a-bean-validation-constraintvalidator/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2010/03/12/unit-testing-a-bean-validation-constraintvalidator/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 15:27:16 +0000</pubDate>
		<dc:creator>Jan-Kees van Andel</dc:creator>
				<category><![CDATA[Java API]]></category>
		<category><![CDATA[Java EE]]></category>
		<category><![CDATA[Java language]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[annotations]]></category>
		<category><![CDATA[bean validation]]></category>
		<category><![CDATA[ConstraintValidator]]></category>
		<category><![CDATA[Dynamic Proxies]]></category>
		<category><![CDATA[JUnit]]></category>
		<category><![CDATA[Mockito]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/blog/?p=976</guid>
		<description><![CDATA[I&#8217;ve been playing a bit with Bean Validation and thought I found an issue: Unit testing a ConstraintValidator. Specifically, parametrized ConstraintValidators.
First, what&#8217;s a parametrized ConstraintValidator? Simple, a Validator that takes a parameter to do its job. A simple example is a length validator that takes the minimum and maximum length as parameters and validates if [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been playing a bit with Bean Validation and thought I found an issue: Unit testing a ConstraintValidator. Specifically, parametrized ConstraintValidators.</p>
<p>First, what&#8217;s a parametrized ConstraintValidator? Simple, a Validator that takes a parameter to do its job. A simple example is a length validator that takes the minimum and maximum length as parameters and validates if the value is between those two.</p>
<p>Parametrized ConstraintValidators are everywhere, even Bean Validation itself contains them. For example: @Min(length) and @Max(length), but also normal ConstraintValidators, like @NotNull where you can customize the error message. However, this error message parameter is not very interesting with regards to unit testing individual ConstraintValidators, because the message is generated by the Bean Validation framework.</p>
<p>For example, consider this ConstraintValidator, incl. corresponding annotation:</p>
<pre><script type="syntaxhighlighter" class="brush: java">
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = CreditCardExpiryYearValidator.class)
public @interface CreditCardExpiryYear {
    int expirationInYears() default 10;
    String message() default "{validation.CreditCardExpiryYear.message}";
}

public class CreditCardExpiryYearValidator implements ConstraintValidator&lt;CreditCardExpiryYear, Integer&gt; {
    private volatile int expirationInYears;
    public void initialize(CreditCardExpiryYear constraint) {
        this.expirationInYears = constraint.expirationInYears();
    }

    public boolean isValid(Integer year, ConstraintValidatorContext context) {
        final int nowYear = Calendar.getInstance().get(Calendar.YEAR);
        return year != null
            &amp;&amp; year &lt; nowYear + expirationInYears;
    }
}
</script></pre>
<p>In the future, Bean Validation may become the core mechanism for ensuring correctness in your system. For example, JPA 2.0 leverages Bean Validation annotations to generate additional DDL statements and JSF 2.0 automatically uses Bean Validation when it&#8217;s available. Note: JSF 2.0 uses a new concept, called &#8220;default validators&#8221; to implement this. A default validator is invoked on every input component on a postback.</p>
<p>But, how do we test this stuff? After all, you can&#8217;t instantiate an annotation.</p>
<p>I currently have 4 options:</p>
<ul>
<li><a href="#reflection">Using reflection to use a declared annotation</a></li>
<li><a href="#implementation">Custom annotation implementation</a></li>
<li><a href="#dynamic_proxies">Dynamic proxies</a></li>
<li><a href="#mockito">Mocking, for example using Mockito</a></li>
</ul>
<p><b><a name="reflection">Using a declared annotation</a></b><br />
The first attempt is shown below. Here, I simply declare the annotation in my test case on a dummy instance field (an annotation doesn&#8217;t live on its own) and look it up using reflection. This way, Java takes care of instantiating and initializing the annotation.</p>
<pre><script type="syntaxhighlighter" class="brush: java">
public class CreditCardExpiryYearValidatorTest {

    @CreditCardExpiryYear(expirationInYears = 5)
    int expiryAfter5Years;

    @CreditCardExpiryYear
    int expiryAfter10Years;

    private int currentYear;

    @Before
    public void setUp() throws Exception {
        currentYear = Calendar.getInstance().get(Calendar.YEAR);
    }

    @Test
    public void testIsValid_DefaultExpiration() throws Exception {
        CreditCardExpiryYearValidator val = new CreditCardExpiryYearValidator();
        val.initialize(getFieldAnnotation(this, "expiryAfter10Years", CreditCardExpiryYear.class));

        boolean b = val.isValid(currentYear + 5, null);

        assertTrue(b);
    }

    @Test
    public void testIsValid_Configure5Years() throws Exception {
        CreditCardExpiryYearValidator val = new CreditCardExpiryYearValidator();
        val.initialize(getFieldAnnotation(this, "expiryAfter5Years", CreditCardExpiryYear.class));

        boolean b = val.isValid(currentYear + 6, null);

        assertFalse(b);
    }
}
</script></pre>
<p>I personally quite like this approach. The test data is inside the test case. Unfortunately not in the test method, that would be better, but since you can&#8217;t put annotations everywhere in your code, it&#8217;s not easy to implement this decently.</p>
<p>So let&#8217;s look at the next one&#8230;</p>
<p><b><a name="implementation">Custom annotation implementation</a></b><br />
Since Java annotations are just a special case of interfaces, they should be fairly straightforward to implement. However, for some reason, I didn&#8217;t know this until recently. But it&#8217;s actually not different from any other interface implementation. See for yourself.</p>
<pre><script type="syntaxhighlighter" class="brush: java">
public class CreditCardExpiryYearValidatorTest {

    private int currentYear;

    @Before
    public void setUp() throws Exception {
        currentYear = Calendar.getInstance().get(Calendar.YEAR);
    }

    @Test
    public void testIsValid_CustomAnnotationImpl() throws Exception {
        CreditCardExpiryYearValidator val = new CreditCardExpiryYearValidator();
        val.initialize(new CreditCardExpiryYearImpl());

        boolean b = val.isValid(currentYear + 6, null);

        assertFalse(b);
    }
}
class CreditCardExpiryYearImpl implements CreditCardExpiryYear {
    public int expirationInYears() { return 5; }
    public String message() { return "hello"; }
    public Class&lt;? extends Annotation&gt; annotationType() { return CreditCardExpiryYear.class; }
}
</script></pre>
<p>Nothing special, right? But I don&#8217;t really like it. I could have also written it inline, but I don&#8217;t like that either:</p>
<pre><script type="syntaxhighlighter" class="brush: java">
@Test
public void testIsValid_CustomAnnotationImplInline() throws Exception {
    CreditCardExpiryYearValidator val = new CreditCardExpiryYearValidator();
    val.initialize(new CreditCardExpiryYear() {
        public Class&lt;? extends Annotation&gt; annotationType() { return CreditCardExpiryYear.class; }
        public String message() { return ""; }
        public int expirationInYears() { return 5; }
    });

    boolean b = val.isValid(currentYear + 6, null);

    assertFalse(b);
}
</script></pre>
<p>I think the above one looks like garbage. So this is also a no-go.</p>
<p><b><a name="dynamic_proxies">Dynamic proxies</a></b><br />
Java itself uses dynamic proxies at runtime to instantiate annotations. So why not also use a Proxy to mock the annotation? See for yourself. </p>
<pre><script type="syntaxhighlighter" class="brush: java">
@Test
public void testIsValid_DynamicProxy() throws Exception {
    CreditCardExpiryYearValidator val = new CreditCardExpiryYearValidator();
    CreditCardExpiryYear annotation = (CreditCardExpiryYear)
            Proxy.newProxyInstance(
                    this.getClass().getClassLoader(),
                    new Class&lt;?&gt;[] { CreditCardExpiryYear.class },
                    new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return 5;
        }
    });
    val.initialize(new CreditCardExpiryYearImpl());
    boolean b = val.isValid(currentYear + 6, null);

    assertFalse(b);
}
</script></pre>
<p>However inline, the implementation looks very clumsy. Unfortunately this is probably as simple as it can get, since you DO need to define the inner class.</p>
<p>And it will become even worse when there are multiple parameters on the bean, since you need to check which method is invoked. This will make the implementation even worse.</p>
<p><b><a name="mockito">Mocking using Mockito</a></b><br />
But, creating and configuring proxies, isn&#8217;t this what mocking libraries do? Exactly, let&#8217;s try.</p>
<pre><script type="syntaxhighlighter" class="brush: java">
@Test
public void testIsValid_Mockito() throws Exception {
    CreditCardExpiryYearValidator val = new CreditCardExpiryYearValidator();
    CreditCardExpiryYear annotation = mock(CreditCardExpiryYear.class);
    when(annotation.expirationInYears()).thenReturn(5);

    val.initialize(annotation);
    boolean b = val.isValid(currentYear + 6, null);

    assertFalse(b);
}
</script></pre>
<p>This looks pretty nice. And it scales well with multiple attributes.</p>
<p>I only doubt it will be the nicest solution when the annotations become more complex. I really don&#8217;t like annotations that contain annotation parameters. Or even worse, arrays of annotation parameters. But reality is, they exist. And if they exist, they also need to be tested. But, OTOH, people who nest annotations probably don&#8217;t mind unreadable unit tests. <img src='http://blog.smart-java.nl/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2010/03/12/unit-testing-a-bean-validation-constraintvalidator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Singleton Smells</title>
		<link>http://blog.smart-java.nl/blog/index.php/2009/04/19/singleton-smells/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2009/04/19/singleton-smells/#comments</comments>
		<pubDate>Sun, 19 Apr 2009 15:05:53 +0000</pubDate>
		<dc:creator>Jan-Kees van Andel</dc:creator>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[patterns]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/blog/?p=370</guid>
		<description><![CDATA[I really hate the Singleton pattern. It makes code hard to test, it has nothing to do with general OO principles and the Singletons I see daily (written by others of course   ) usually look very procedural.
People who use Singletons in Java all the time have more fundamental problems (I&#8217;m not talking about [...]]]></description>
			<content:encoded><![CDATA[<p>I really hate the Singleton pattern. It makes code hard to test, it has nothing to do with general OO principles and the Singletons I see daily (written by others of course <img src='http://blog.smart-java.nl/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ) usually look very procedural.</p>
<p>People who use Singletons in Java all the time have more fundamental problems (I&#8217;m not talking about singleton scope in Spring btw), so I&#8217;m not gonna rant about that problem here, but I do like to show you an alternative which makes it easier to unit test Singletons.</p>
<p>Neal Ford published <a href="http://www.infoq.com/presentations/10-Ways-to-Better-Code-Neal-Ford">a talk on InfoQ</a> called: <i>&#8220;10 Ways to Improve Your Code&#8221;</i>. Item 4: <i>&#8220;Good citizenship&#8221;</i> is about static methods and especially the Singleton design pattern. Static methods have their usage, for example simple stateless utilities like: <a href="http://java.sun.com/javase/6/docs/api/java/lang/Math.html#sqrt(double)">int Math.sqrt(double)</a> or Apache Commons. But when you&#8217;re going to add state into the mix, things get messy. </p>
<h3>Singleton usage</h3>
<p>Let&#8217;s step back. Why are we using Singletons in the first place?</p>
<ol>
<li>First, as the name says, because you want to guarantee that there is only one instance. Typical examples in the Java libraries are <a href="http://java.sun.com/javase/6/docs/api/java/awt/Toolkit.html">java.awt.Toolkit</a> and <a href="http://java.sun.com/javase/6/docs/api/java/io/Console.html">java.io.Console</a>.<br />For those of you interested, Console doesn&#8217;t have a static getConsole method, but can be accessed through <a href="http://java.sun.com/javase/6/docs/api/java/lang/System.html#console()">System.console()</a> and &#8211; in the Sun implementation &#8211; SharedSecrets.getJavaIOAccess().console(). In these cases, a Singleton is needed because there may NEVER be two instances of these classes. Otherwise strange things will happen, because you never know which instance contains the state you need.</li>
<li>Second, and depending on the circumstances this is a good or a bad thing, Singletons are the Object Oriented equivalent of globals. Almost everybody agrees that (non-immutable) globals are very bad, but for some reason, many developers still use Singletons. But, for certain objects, it&#8217;s useful to be able to access them from everywhere, without needing parameters all the time.</li>
</ol>
<p>And of course, there are plenty of myths regarding Singletons, for example because singletons can be lazily instantiated on first use. Well, guess what? Classes are lazily initialized by the ClassLoader, so unless you&#8217;re messing with cyclic initialization dependencies you don&#8217;t need any custom lazy loading mechanism.<br />
By the way, lazy initialization is a bad thing that should be avoided if possible. See <a href="http://java.sun.com/docs/books/effective/">Joshua Bloch&#8217;s Effective Java</a> for more details.</p>
<h3>An example Singleton</h3>
<p>Below is a snippet with an example Singleton. You probably see Singletons like this all day.</p>

<div class="wp_syntax"><div class="code"><pre class="java5" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000000; font-weight: bold;">class</span> BadSingleton <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399; font-weight: bold;">String</span> prop1<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399; font-weight: bold;">String</span> prop2<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> BadSingleton<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">prop1</span> = <span style="color: #003399; font-weight: bold;">System</span>.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prop1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">prop2</span> = <span style="color: #003399; font-weight: bold;">System</span>.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prop2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> BadSingleton INSTANCE = <span style="color: #000000; font-weight: bold;">new</span> BadSingleton<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> BadSingleton getInstance<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> INSTANCE<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Other methods</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>It&#8217;s just a simple Singleton. It uses field initialization for thread safety and simplicity, but is still lazily initialized (by the ClassLoader). Further, initialization is done in the constructor where the environment is queried for some settings.</p>
<p>As you might know, this code is not testable, not even with <a href="http://java.sun.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible(boolean)">reflection/setAccessible(true)</a> hacking, since the field is declared static + final. See the following snippet for a misguided attempt to create a unit test:</p>

<div class="wp_syntax"><div class="code"><pre class="java5" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BadSingletonTest <span style="color: #009900;">&#123;</span>
    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #006600; font-weight: bold;">void</span> testGetInstance_Fail<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399; font-weight: bold;">Exception</span> <span style="color: #009900;">&#123;</span>
        Constructor<span style="color: #339933;">&lt;</span>BadSingleton<span style="color: #339933;">&gt;</span> constructor = BadSingleton.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getDeclaredConstructor</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        constructor.<span style="color: #006633;">setAccessible</span><span style="color: #009900;">&#40;</span><span style="color: #006600; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        BadSingleton obj1 = constructor.<span style="color: #006633;">newInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399; font-weight: bold;">Field</span> field = BadSingleton.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getDeclaredField</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;INSTANCE&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        field.<span style="color: #006633;">setAccessible</span><span style="color: #009900;">&#40;</span><span style="color: #006600; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        field.<span style="color: #006633;">set</span><span style="color: #009900;">&#40;</span><span style="color: #006600; font-weight: bold;">null</span>, obj1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Exception because INSTANCE is static + final</span>
        BadSingleton obj1 = BadSingleton.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        BadSingleton obj2 = BadSingleton.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #006633;">assertSame</span><span style="color: #009900;">&#40;</span>obj1, obj2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>An alternative for this issue would be lazy initialization, but this has the disadvantages of not being thread safe when not synchronized correctly. <a href="http://www.javaconcurrencyinpractice.com/">Java Concurrency in Practice</a> by Brian Goetz is a must-read when you are interested in thread safety issues.</p>
<h3>Alternative using a factory</h3>
<p>This is the alternative Singleton class. It&#8217;s a modified version of Neal&#8217;s example.</p>

<div class="wp_syntax"><div class="code"><pre class="java5" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000000; font-weight: bold;">class</span> GoodSingleton <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399; font-weight: bold;">String</span> prop1<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399; font-weight: bold;">String</span> prop2<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> GoodSingleton<span style="color: #009900;">&#40;</span><span style="color: #003399; font-weight: bold;">String</span> prop1, <span style="color: #003399; font-weight: bold;">String</span> prop2<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">prop1</span> = prop1<span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">prop2</span> = prop2<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Other methods</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The responsibility of instantiating the Singleton is programmed into the Factory, which is shown below:</p>

<div class="wp_syntax"><div class="code"><pre class="java5" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> GoodSingletonFactory <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> GoodSingleton INSTANCE<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399; font-weight: bold;">String</span> prop1 = <span style="color: #003399; font-weight: bold;">System</span>.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prop1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399; font-weight: bold;">String</span> prop2 = <span style="color: #003399; font-weight: bold;">System</span>.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prop2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            Constructor<span style="color: #339933;">&lt;</span>GoodSingleton<span style="color: #339933;">&gt;</span> constructor = GoodSingleton.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getDeclaredConstructor</span><span style="color: #009900;">&#40;</span><span style="color: #003399; font-weight: bold;">String</span>.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #003399; font-weight: bold;">String</span>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            constructor.<span style="color: #006633;">setAccessible</span><span style="color: #009900;">&#40;</span><span style="color: #006600; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            INSTANCE = constructor.<span style="color: #006633;">newInstance</span><span style="color: #009900;">&#40;</span>prop1, prop2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399; font-weight: bold;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399; font-weight: bold;">RuntimeException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;error initializing &quot;</span> + GoodSingletonFactory.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> GoodSingleton getInstance<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> INSTANCE<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>As shown in the snippet, the factory uses reflection to access the private constructor. Note that this trick only works if there is no SecurityManager or if the active SecurityManager approves this action.</p>
<p>It&#8217;s also a little bit less &#8220;Singleton&#8221; since it is possible to have more than one instance. The same reflection trick we used, now works a bit against us. If this is not an issue for you, it doesn&#8217;t matter. After all, developers who want to abuse your API always succeed if they really want to.</p>
<p>But we do get the advantage of better testability, as shown in the following two snippets:</p>

<div class="wp_syntax"><div class="code"><pre class="java5" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> GoodSingletonTest <span style="color: #009900;">&#123;</span>
    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #006600; font-weight: bold;">void</span> testConstructor_Ok<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399; font-weight: bold;">Exception</span> <span style="color: #009900;">&#123;</span>
        Constructor<span style="color: #339933;">&lt;</span>GoodSingleton<span style="color: #339933;">&gt;</span> constructor = GoodSingleton.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getDeclaredConstructor</span><span style="color: #009900;">&#40;</span><span style="color: #003399; font-weight: bold;">String</span>.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #003399; font-weight: bold;">String</span>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        constructor.<span style="color: #006633;">setAccessible</span><span style="color: #009900;">&#40;</span><span style="color: #006600; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        GoodSingleton obj1 = constructor.<span style="color: #006633;">newInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1&quot;</span>, <span style="color: #0000ff;">&quot;2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Assert stuff</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="java5" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> GoodSingletonFactoryTest <span style="color: #009900;">&#123;</span>
    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #006600; font-weight: bold;">void</span> testGetInstance_Only_one_instance<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399; font-weight: bold;">Exception</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003399; font-weight: bold;">System</span>.<span style="color: #006633;">setProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prop1&quot;</span>, <span style="color: #0000ff;">&quot;test value&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399; font-weight: bold;">System</span>.<span style="color: #006633;">setProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prop2&quot;</span>, <span style="color: #0000ff;">&quot;test value&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        GoodSingleton instance1 = GoodSingletonFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #006633;">assertNotNull</span><span style="color: #009900;">&#40;</span>instance1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        GoodSingleton instance2 = GoodSingletonFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #006633;">assertNotNull</span><span style="color: #009900;">&#40;</span>instance2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #006633;">assertSame</span><span style="color: #009900;">&#40;</span>instance1, instance2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>As you can see, testing now becomes trivial.</p>
<h3>Notes</h3>
<p>Choosing the factory approach has some effects that may be important to you. Here&#8217;s a list of consequences and random thoughts.</p>
<ul>
<li>When using the reflection approach, it is possible for developers to mess up the Singleton behavior using reflection. When they do this, you may end up with multiple instances, which may be undesirable. When using a Singleton and the instance field is declared as static + final, this is not possible. The importance of this point differs per situation.</li>
<li>You can choose to make the constructor package private (default) accessible. This way, you don&#8217;t need reflection to access it from the same package. If you put the Factory and the unit tests in the same package, this will make the code much more readable, especially for less experienced developers. It&#8217;s also less error prone, because the compiler isn&#8217;t capable of doing thorough checks on reflective code. On the other hand, if a developer put&#8217;s a custom class in the same package, it&#8217;s possible to invoke the constructor and thus create multiple instances.</li>
<li>There is a myth that reflection is slow. It&#8217;s true that reflection is not as fast as JIT optimized (plain Java) bytecode. But since about 2000, there have been massive improvements in reflective invocation performance. And of course, if you look at the snippets, reflection is only used the first time.</li>
<li>Using a static initializer block in the Factory and an immutable (all fields final, no lazy initialization) Singleton class makes the entire structure less sensitive to Concurrency hazards. Again, see Brian Goetz&#8217; book for details.</li>
</ul>
<p>If you ask me, the advantages outweigh the disadvantages by miles, especially when you consider that when developers misbehave (like in the first two bullets) in such a way that they break the Singleton principle, they should (and on my projects will) be ass whooped. <img src='http://blog.smart-java.nl/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2009/04/19/singleton-smells/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Domain Driven Design in de Referentie Architectuur.</title>
		<link>http://blog.smart-java.nl/blog/index.php/2009/02/19/domain-driven-design-in-de-referentie-architectuur/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2009/02/19/domain-driven-design-in-de-referentie-architectuur/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 15:01:02 +0000</pubDate>
		<dc:creator>Pieter van Boxtel</dc:creator>
				<category><![CDATA[Algemeen]]></category>
		<category><![CDATA[Architectuur]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/blog/?p=306</guid>
		<description><![CDATA[In de huidige versie van de Referentie Architectuur hebben we verklaard aanhanger te zijn van Domain Driven Design. We hebben domein objecten gedefinieerd, maar wat doen we nu eigenlijk met het gedachtengoed van Evans? Een van de doelen voor de volgende versie is te kijken of we de patterns van DDD een plekje kunnen geven. [...]]]></description>
			<content:encoded><![CDATA[<p>In de huidige versie van de Referentie Architectuur hebben we verklaard aanhanger te zijn van Domain Driven Design. We hebben domein objecten gedefinieerd, maar wat doen we nu eigenlijk met het gedachtengoed van Evans? Een van de doelen voor de volgende versie is te kijken of we de patterns van DDD een plekje kunnen geven. Hieronder een poging daartoe, waarbij ik niet al te veel beschrijving of uitleg van de patterns geef. Voor een goede uitleg van de patterns is een niet te overtreffen bron, en dat is het <a href="http://domaindrivendesign.org/books/index.html#DDD" target="_blank">boek van Evans</a>.</p>
<p>Evans beschijft eigenlijk twee soorten patterns. De eerste soort geeft een onderscheid in typen objecten en methoden. Deze patterns zijn concreet terug te zien in een domein model. Dit zijn de patterns waar we echt iets mee kunnen in de referentie architectuur. De tweede soort zijn eerder proces patterns. Deze beschrijven wat abstractere doelen en wegen naar deze doelen. Deze patterns zijn moeilijk concreet te maken in een referentie architectuur en ze komen hier verder niet meer aan bod.</p>
<p>Kern van een DDD domein model zijn <strong>Entities (89)</strong> en <strong>Value Objects (97)</strong>. Dit zijn de klassieke OO objecten met een toestand en gedrag. Entities zijn objecten met een “identiteit”. Ze zijn niet uitwisselbaar. Ze kunnen gedurende hun levensduur veranderen, maar ze blijven uniek. Een persoon object is in de regel een Entity. Een persoon wordt ouder, zijn uiterlijk verandert, allerlei attributen wijzigen, maar een persoon blijft dezelfde identiteit. Value Objects daarentegen zijn wel uitwisselbaar. In een klantencontactsysteem is een adres niets meer dan een verzameling attributen. Een adres object kan hergebruikt worden, maar dat hoeft niet. Het maakt niet uit als in het systeem twee adres objecten geïnstantieerd zijn met hetzelfde adres. En als een persoon en zijn adres uit memory verdwijnen, dan is het wanneer de persoon opnieuw opgevraagd wordt niet belangrijk dat hetzelfde adres object teruggevonden wordt. (Voor een kadastraal systeem gaat deze redenatie uiteraard niet op&#8230;)</p>
<p>Onderscheid tussen Entities en Value Objects is waardevol bij het ontwerp van een applicatie. We kunnen andere ontwerpregels op deze typen objecten loslaten. Zo is het een goed idee om Value Objects immutable te maken. Wanneer een attribuut dient te wijzigen vervangen we het object gewoon door een nieuwe instantie. Fowler definieerde het onderscheid tussen Entities en Value Objects al in <a title="Patterns of Enterprise Application Architecture" href="http://www.martinfowler.com/books.html#eaa">Patterns of Enterprise Application Architecture</a>. Hij lijkt Value Objects echter te suggereren voor algemene, herbruikbare zaken, zoals Money. Evans gebruikt het onderscheid structureler door elk “klassiek” domein object in een van beide hokjes te duwen. Bijvoorbeeld in een facturatie systeem kunnen we facturen modelleren als Entities en factuurregels als Value Objects.</p>
<p>Ook geeft Evans enkele richtlijnen voor het opstellen van Entities en Value Objects:</p>
<ul>
<li>Gebruik <strong>Intention-Revealing Interfaces (246)</strong>, waarbij namen van klassen en methoden hun effect en doel beschrijven.</li>
<li>Gebruik <strong>Side-Effect-Free Functions (250)</strong>, factor deze uit in Value Objects en maak er <strong>Closed Operations (268)</strong> van.</li>
<li>Maak daarentegen van Entity methodes die de state wijzigen commands die geen domein klassen teruggeven. Gebruik <strong>Assertions (255)</strong> om post-condities en invarianten van deze methodes te controleren.</li>
</ul>
<p><strong>Services (104)</strong> zijn objecten met enkel gedrag. Ze bevatten methoden die geen logische plek hebben in een Entity of Value Object. De naam &#8216;Service&#8217; is enigszins verwarrend aangezien de term &#8217;service&#8217; in de Referentie Architectuur en andere architecturen in een andere context gebruikt wordt. Een betere naam is wellicht &#8216;Domain Service&#8217;.</p>
<p>Entities en Value Objects zijn de objecten in het domein model die gepersisteerd worden. <strong>Factories (136)</strong> en <strong>Repositories (147)</strong> zijn de domein objecten die voor persistentie verantwoordelijk zijn. Factories creëren domein objecten en Repositories bieden zoek-ingangen. Een Factory is in feite geen afzonderlijk type object. Een Factory wordt gerealiseerd door middel van een Factory Method (GoF) op een Entity of op een al dan niet speciaal voor het doel gecreëerde Service. Door vanuit de Factory Method te delegeren naar een &#8216;add&#8217; methode op een Repository bewerkstelligen we dat database logica in één type domeinobject gecentreerd wordt.</p>
<p>De eenheid voor persistentie is een <strong>Aggregate (125)</strong>. Dit is verzameling van een of meerdere entities en value objects, waarbij één entity, de root, als aanspreekpunt fungeert. Alle niet-root objecten in de aggregate staan uitsluitend ter dienste van de root en objecten buiten de aggregate hebben uitsluitend relaties naar de aggregate root.</p>
<p>Verder kunnen domeinobjecten gegroepeerd worden in <strong>Modules (109)</strong>, om zodoende structuur te creëren in het domeinmodel. Modules of Packages zijn standaard concepten in OO programmeertalen en modelleertechnieken.</p>
<p>Een <strong>Specification (224)</strong> tenslotte is een eenvoudig Value Object dat een (of meerdere) business rule controleert voor een ander object. Specifications zijn gebaseerd op predicatenlogica waardoor ze als logische condities zijn te combineren tot complexere business rules. Een Specification kan drie doelen hebben:</p>
<ol>
<li><em>Validatie</em> van een business rule op een object. Een toepassing hiervan is de manier waarop Mod4J met business rules in de domein DSL omgaat.</li>
<li>Een <em>selectie</em> criterium specificeren om een object uit een selectie te selecteren. Een toepassing hiervan is gebruik van een Specification als parameter voor een Repository.</li>
<li><em>Bouw</em> van een nieuw object specificeren.</li>
</ol>
<p>Onderstaand plaatje toont bovenstaande patterns en hun relaties:</p>
<p style="text-align: center;"><a href="http://blog.smart-java.nl/blog/wp-content/uploads/2009/02/ddd.png"><img class="size-medium wp-image-309 aligncenter" title="ddd" src="http://blog.smart-java.nl/blog/wp-content/uploads/2009/02/ddd.png" alt="" width="587" height="411" /></a></p>
<p>De hierboven genoemde patterns kunnen we zonder al te grote gevolgen in de referentie architectuur opnemen ter vervanging van / uitbreiding op de huidige typen business componenten. De vertaling gaat dan als volgt:</p>
<ul>
<li>De huidige Referentie Architectuur kent Business Processen, welke vergelijkbaar lijken met Domain Services. Business Processen zijn echter geen onderdeel van het domein model, ze worden niet aangeroepen door domein objecten. Verder stelt de Referentie Architectuur dat elke aanroep van een domein object via een business process gaat. In feite hebben we met deze Business Processen een extra “laagje” gecreëerd dat redundant is, aangezien erboven zich een verplichte servicelaag bevindt. Niets let ons om dat laagje te schrappen en domain services alleen te definieren als ze een toegevoegde waarde hebben.</li>
<li>De domein objecten zoals we ze nu kennen kunnen we onderverdelen in Entities en Value Objects.</li>
<li>Aggregates worden nu wel genoemd in de implementation view als eenheid van persistentie, maar ze worden niet expliciet onderkend als modelleereenheid in de logische view.</li>
<li>Specifications zijn nieuw ten opzichte van de referentie architectuur, hoewel Mod4J ze wel al toepast voor business rules.</li>
<li>Repositories zitten nu in een afzonderlijke laag, de datalaag, en heten Data Access Logic component. Echter, zoals ik in een <a title="Lagen in de referentiearchitectuur" href="http://blog.smart-java.nl/blog/index.php/2008/10/06/lagen-in-de-referentiearchitectuur/" target="_blank">vorige blog</a> betoogde is dat niet terecht en horen ze in de domeinlaag thuis.</li>
<li>Volgens diezelfde blog zijn de Service Agents en Data Service Agents zoals we ze nu kennen dezelfde dingen en kunnen we ze onderbrengen in een (nieuwe) laag, de Integratielaag.</li>
</ul>
<p>Mijn conclusie is dat we door toepassing van de DDD patterns de referentie architectuur consistenter en begrijpelijker kunnen maken. In het ontwerp van een applicatie komt meer structuur, terwijl het resultaat, de implementatie, nagenoeg niet wijzigt ten opzichte van de huidige referentie architectuur. Bijkomend voordeel van toepassing van DDD is dat we voor de educatie van de architectuur kunnen verwijzen naar het boek “Domain Driven Design” van Evans.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2009/02/19/domain-driven-design-in-de-referentie-architectuur/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Boekbespreking: Code Complete, 2nd Edition</title>
		<link>http://blog.smart-java.nl/blog/index.php/2009/01/21/boekbespreking-code-complete-2nd-edition/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2009/01/21/boekbespreking-code-complete-2nd-edition/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 16:06:15 +0000</pubDate>
		<dc:creator>Hedzer Westra</dc:creator>
				<category><![CDATA[Boeken]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Methodologieën]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[patterns]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/blog/?p=282</guid>
		<description><![CDATA[
 
Auteur: Steve McConnell, publicatiejaar: 2004, pagina’s: 906, ISBN-13: 978-0735619678, website: http://www.cc2e.com/, Amazon rating: 5 sterren.
 
Code Complete was me jaren geleden aangeraden als hét boek (‘de bijbel’) om te leren nette code te produceren. Enige tijd geleden (!) is de tweede editie uitgekomen, wat me een goed moment leek om deze eens te bestuderen. Het viel [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"><a href="http://blog.smart-java.nl/blog/wp-content/uploads/2009/01/cc2e.bmp"><img class="alignnone size-medium wp-image-283" title="cc2e" src="http://blog.smart-java.nl/blog/wp-content/uploads/2009/01/cc2e.bmp" alt="" /></a></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"> </p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Auteur:<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Steve McConnell</span>, publicatiejaar: 2004, pagina’s: 906, ISBN-13: 978-0735619678, website: <span style="mso-ansi-language: EN-US;" lang="EN-US"><a href="http://www.cc2e.com/"><span style="mso-ansi-language: NL;" lang="NL">http://www.cc2e.com/</span></a></span>,<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Amazon</span><span lang="EN-AU"> </span>rating: 5 sterren.</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Code Complete was me jaren geleden aangeraden als hét boek (‘de bijbel’) om te leren nette code te produceren. Enige tijd geleden (!) is de tweede editie uitgekomen, wat me een goed moment leek om deze eens te bestuderen. Het viel me gelijk op dat deze dikke pil van Microsoft<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Press</span> afkomstig is; auteur<span style="mso-ansi-language: EN-AU;"> <span lang="EN-AU">Steve McConnell</span></span><span lang="EN-AU"> </span>komt uit de (Microsoft) wereld van C-programmeurs, maar beheerst vele andere talen.</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Het boek geeft de lezer diverse praktische, aan de praktijk gestaafde, gedetailleerde tips en voorbeelden om op een juiste manier programmacode te maken. De meeste voorbeelden gaan uit van C++, Visual<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Basic</span>, Java en C# (in die volgorde). Daar zit ’m wat mij betreft ook meteen een manco: ikzelf ben niet (meer) geïnteresseerd in allerlei tips om onder anderen netjes met pointers en globale variabelen om te gaan. Dat heeft Java netjes voor me afgeschermd… Wel krijg je een interessant kijkje in de keuken van C/C++, en wat extra respect voor programmeurs daarin, die zelfdiscipline nodig hebben, waar wij de taal Java hebben om dezelfde mate van noodzakelijke restrictie te krijgen.</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">De structuur, lay-out en leesbaarheid van het boek is zeer goed: er is op een prettig leesbare manier geschreven, hier en daar humoristisch en nergens flauw. Een uitgebreide inhoudsopgave, lijst van tabellen &amp; figuren, referenties, leeslijst van tijdschriften en boeken, en index ontbreken niet. Elk hoofdstuk begint met een duidelijke inleiding van de inhoud, en eindigt met een checklist, samenvatting van de <span style="mso-ansi-language: EN-AU;" lang="EN-AU">‘key points</span>’ en vele referenties naar extra leesvoer. Dat laatste is erg opvallend:<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Steve</span> heeft ontzettend veel materiaal gebruikt bij het samenstellen van dit boek. In het voorwoord claimt hij dan ook dat zijn boek een samenvatting is van heel veel (zo niet alle) succesvolle ontwikkelingen en ontdekkingen op het gebied van softwareconstructie. Overal in het boek staan in de kantlijn referenties naar de ‘cc2e’ website met meer informatie, betekenisvolle quotes van bekende IT-goeroes en kruisverwijzingen. Naast verwijzingen naar onderzoeksresultaten van academici, veelal met statistische gegevens, put de auteur ook uit zijn eigen rijke ervaringen bij o.a. Microsoft, Boeing en NASA. Veel stukken code worden begeleid door een “coding horror” icoontje, om aan te geven hoe verschrikkelijk het desbetreffende antivoorbeeld is.</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Het boek omvat 6 delen, onderverdeeld in 35 hoofdstukken, elk met hun eigen onderwerp. Teveel om allemaal te noemen, maar enkele sappige details &amp; citaten wil ik je niet onthouden:</span></p>
<ul style="margin-top: 0cm;" type="disc">
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small;"><span style="font-family: Times New Roman;"><em style="mso-bidi-font-style: normal;">“</em><em style="mso-bidi-font-style: normal;"><span style="mso-ansi-language: EN-GB;" lang="EN-GB">Software Construction is the only activity that is guaranteed to be done</span>”</em>: dit is een stevig argument voor Agile werken – waarin documentatie een ondergeschikte rol krijgt toebedeeld ten gunste van productie van programmacode.</span></span></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small;"><span style="font-family: Times New Roman;"><em style="mso-bidi-font-style: normal;">“</em><em style="mso-bidi-font-style: normal;"><span style="mso-ansi-language: EN-GB;" lang="EN-GB">Program into, not in, a language</span>”</em>: hiermee wil<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Steve</span> je aanzetten om de mogelijkheden van je taal wijselijk te gebruiken, en niet blind alle mogelijkheden – al dan niet op een verkeerde wijze – toe te passen.</span></span></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small; font-family: Times New Roman;">De sectie over complexiteit en het beperkte menselijke begripsvermogen is erg vermakelijk.</span></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><em style="mso-bidi-font-style: normal;"><span style="mso-ansi-language: EN-GB;" lang="EN-GB"><span style="font-size: small;"><span style="font-family: Times New Roman;">“Don’t optimise your code, unless a profiler or production problem forces you to.”</span></span></span></em></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small; font-family: Times New Roman;">Als alternatief voor nette UML ontwerpen: neem foto’s van tekeningen op<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> whiteboard</span>, of bewaar flip-overs.</span></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small; font-family: Times New Roman;">Itereer je design.</span></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small; font-family: Times New Roman;">Gebruik tijdens ontwikkeling asserts of excepties die je programma hard doen crashen, maar zorg dat in de productieversie dezelfde fout netjes (liefst zonder interactie van, en overlast voor, de gebruiker) wordt afgehandeld. Dit wordt ook wel<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> offensive</span> vs.<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> defensive programming</span> genoemd.</span></li>
<li class="MsoNormal" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;"><span style="font-size: small; font-family: Times New Roman;">Schrijf alles altijd uit in pseudo-code. Persoonlijk doe ik dit zeer zelden – en ik heb uit dit boek ook geen extra stimulans daarvoor gehaald, onder anderen door het detailniveau dat wordt aangeraden.</span><span style="font-size: small; font-family: Times New Roman;"> </span></li>
</ul>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Veel van de onderwerpen die beschreven worden –<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> requirements</span>, design, optimalisatie,<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> naming convention</span>, (unit)<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> testing</span>, Design<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> Patterns</span>, encapsulatie, factorisatie,<span style="mso-ansi-language: EN-AU;" lang="EN-AU"> assert</span> vs. excepties vs. <span style="mso-ansi-language: EN-AU;" lang="EN-AU">unit tests, continuous integration, comments vs. refactoring</span> – waren eerlijk gezegd een samenvatting van wat ik al wist. Nuttig om hier en daar iets nieuws te horen, of om even opgefrist te worden, maar echt iets fundamenteels geleerd: nee.</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Wat pijnlijk duidelijk wordt, is dat het boek geschreven is vlak voordat Java5 uitkwam – hier en daar wordt Java verweten enkele mogelijkheden te ontberen, terwijl we die al jaren tot onze beschikking hebben.</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Concluderend: het boek maakt wat mij betreft zijn belofte slechts gedeeltelijk waar. Voor C++/C#/VB programmeurs is het vast en zeker erg bruikbaar, maar voor Java is het net iets te oud, en ligt er te weinig focus op problemen in Java. Als je junior of medior bent, of voor een breed scala aan onderwerpen in software constructie met één boek klaar wilt zijn, is het een <span style="text-decoration: underline;">goed</span> boek, maar helaas geen <span style="text-decoration: underline;">uitstekend</span> boek…</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;"> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small; font-family: Times New Roman;">Kleurindicatie: <strong style="mso-bidi-font-weight: normal;"><span style="color: #ffcc00;">Amber</span></strong> (2 op schaal van 3)</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"> </p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 12pt; font-family: &quot;Times New Roman&quot;; mso-ansi-language: NL; mso-fareast-font-family: 'Times New Roman'; mso-fareast-language: NL; mso-bidi-language: AR-SA;">Hierbij nodig ik al mijn collega’s uit om ook boekbesprekingen te publiceren op de J-Tech blog, en tevens informatie te plaatsen op de Wiki (<a href="https://wiki.ordina.nl/confluence/display/GENBIEB/Alle+Boeken">https://wiki.ordina.nl/confluence/display/GENBIEB/Alle+Boeken</a>), zodat iedereen een goede keus kan maken uit de vele boeken waarmee je je vaardigheden en kennis kunt uitbreiden. Ikzelf hoop binnenkort te komen met een bespreking van “Programming in Scala,” het eerste boek over deze nieuwe en spannende programmeertaal.</span></p>
<p><span style="font-size: 12pt; font-family: &quot;Times New Roman&quot;; mso-ansi-language: NL; mso-fareast-font-family: 'Times New Roman'; mso-fareast-language: NL; mso-bidi-language: AR-SA;">Hedzer Westra</span></p>
<p><span style="font-size: 12pt; font-family: &quot;Times New Roman&quot;; mso-ansi-language: NL; mso-fareast-font-family: 'Times New Roman'; mso-fareast-language: NL; mso-bidi-language: AR-SA;"><a href="http://blog.smart-java.nl/blog/wp-content/uploads/2009/01/hedzerwestra_93x123.jpg"><img class="alignnone size-medium wp-image-284" title="hedzerwestra_93x123" src="http://blog.smart-java.nl/blog/wp-content/uploads/2009/01/hedzerwestra_93x123.jpg" alt="" width="93" height="123" /></a></span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2009/01/21/boekbespreking-code-complete-2nd-edition/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spring en EasyMock</title>
		<link>http://blog.smart-java.nl/blog/index.php/2008/04/24/spring-en-easymock/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2008/04/24/spring-en-easymock/#comments</comments>
		<pubDate>Thu, 24 Apr 2008 20:23:22 +0000</pubDate>
		<dc:creator>Ron Thijssen</dc:creator>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[Tools/Frameworks]]></category>
		<category><![CDATA[easymock]]></category>
		<category><![CDATA[functional]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[unit]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/?p=26</guid>
		<description><![CDATA[Unit tests hebben zichzelf allang bewezen. Ze zijn erg krachtig doordat ze in een korte cyclus feedback kunnen geven over de kwaliteit van je code. Door continuous integration pakketten in te zetten, word je nog eens persoonlijk erop gewezen dat de code wijziging die je zojuist doorgevoerd hebt geen nieuwe fouten heeft geïntroduceerd. Ontwikkelaars maken [...]]]></description>
			<content:encoded><![CDATA[<p>Unit tests hebben zichzelf allang bewezen. Ze zijn erg krachtig doordat ze in een korte cyclus feedback kunnen geven over de kwaliteit van je code. Door continuous integration pakketten in te zetten, word je nog eens persoonlijk erop gewezen dat de code wijziging die je zojuist doorgevoerd hebt geen nieuwe fouten heeft geïntroduceerd. Ontwikkelaars maken immers nooit fouten <img src='http://blog.smart-java.nl/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Zoals het hoort plaatst iedere ontwikkelaar zijn business logic netjes in services en de data acces komt netjes in Data Access Objects. In dit voorbeeld wil ik laten zien hoe je op functioneel niveau je code kan testen zonder dat hier data access voor nodig is. Dus met de constraint dat de code niet met de database mag communiceren. Aangezien we framework freaks zijn en we allemaal Spring gebruiken vanwege dependency injection en het assembleren van objecten gaan we dit ook toepassen in onze testcases. We hebben onze bean definities namelijk al tot onze beschikking. Hierin staan bijvoorbeeld services, dao&#8217;s, iterators, processors.</p>
<p>We beginnen even met een voorbeeldje van een testcase.</p>
<pre><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@RunWith</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">(SpringJUnit4ClassRunner.</span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">)</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@ContextConfiguration</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">(locations={</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"classpath:services.xml"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">, </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"classpath:data.xml"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">})</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">public</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> ServiceTest </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">extends</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> TestCase{</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p> </o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@Autowired</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">private</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> LoginService </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">loginService</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">;</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p> </o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@Test</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">public</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">void</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> login() {</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>            </span>User result = </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">loginService</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">.login(</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">, </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">);</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>            </span></span><em><span style="font-size: 10pt; font-family: 'Courier New'; color: black">assertEquals</span></em><span style="font-size: 10pt; font-family: 'Courier New'; color: black">(result.getUsername(), </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black">);</span><span style="font-size: 10pt; font-family: 'Courier New'"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black"><span>      </span>}<o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black">}</span>
</pre>
<p>Op dit moment krijgt de <em>LoginService </em>een <em>HibernateUserDaoImpl </em>geïnjecteerd om mee te communiceren. Maar omdat we geen data access willen moeten we deze <em>UserDao </em>vervangen. We komen helaas niet weg met het maken van een DAO-stub. Voor UPDATE en INSERT statements zou het eventueel kunnen, maar zodra een query een bepaalde resultset terug moet geven hang je. We moeten dus een nieuwe <em>UserDao </em>maken met afwijkend gedrag. Kortom; mocken. Nu kunnen we zelf een nieuwe <em>TestUserDaoImpl </em>maken, maar dit introduceert een extra class per testcase (mits we het gedrag van de <em>TestUserDaoImpl </em>willen kunnen veranderen per testcase.) Een betere optie is om gebruik te maken van het mocking framework <a href="http://www.easymock.org/" target="_blank">EasyMock</a>.</p>
<p>Middels EasyMock kunnen we eenvoudig mock objecten maken en declaratief van gedrag voorzien. Het instantiëren van een mock object is relatief eenvoudig:</p>
<pre><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">UserDao userDao = EasyMock.<em>createMock</em>(UserDao.</span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">);</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span></pre>
<p>vervolgens kunnen we met expect scripts het gedrag van de <em>userDao </em>aanpassen. Vervolgens zullen we handmatig deze <em>userDao </em>in onze <em>loginService </em>moeten injecteren….</p>
<p>Maar laat Spring daar nu juist net zo goed in zijn. Je raadt het al; we gaan <a href="http://springframework.org/" target="_blank">Spring </a>gebruiken om mock objecten te injecteren.</p>
<p>We beginnen met het maken van een bean configuratie die we enkel voor test gaan gebruiken:</p>
<pre>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: teal" lang="EN-US">&lt;</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #3f7f7f" lang="EN-US">bean </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f007f" lang="EN-US">id</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">=</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"userDao" </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f007f" lang="EN-US">class</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">=</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"org.easymock.EasyMock"</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f007f" lang="EN-US">factory-method</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">=</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"createMock"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: teal" lang="EN-US">&gt;</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: teal">&lt;</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #3f7f7f">constructor-arg </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f007f">value</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black">=</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff">"nl.ordina.dao.UserDao" </span><span style="font-size: 10pt; font-family: 'Courier New'; color: teal">/&gt;
&lt;/</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #3f7f7f">bean</span><span style="font-size: 10pt; font-family: 'Courier New'; color: teal">&gt;</span></pre>
<p>Bovenstaande bean configuratie maakt gebruik van de factory-method argument, waardoor Spring objecten kan instantiëren middels een factory method. In dit geval is dat EasyMock.createMock(Class&lt;T&gt; class); Als constructor-argument hoeven we enkel de fully qualified classname mee te geven. Spring zal automatisch deze waarde parsen naar een Class. Omdat de UserDao een interface is gebruiken we org.easymock.EasyMock. Indien je een class wil mocken gebruik dan de classextension package van EasyMock.</p>
<p>Als we nu naar onze testcase gaan kijken ziet deze er als volgt uit.</p>
<pre>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@RunWith</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">(SpringJUnit4ClassRunner.</span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">)</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@ContextConfiguration</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">(locations={</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"classpath:services.xml"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">, </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"classpath:test-data.xml"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">})</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">public</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> ServiceTest </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">extends</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> TestCase{</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p> </o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@Autowired</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">private</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> LoginService </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">loginService</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">;</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@Autowired</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">private</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> UserDao </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">userDao</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">;</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@Test</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span></span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">public</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">void</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> login() {</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>            </span>User result = </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">loginService</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">.login(</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">, </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">);</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>            </span></span><em><span style="font-size: 10pt; font-family: 'Courier New'; color: black">assertEquals</span></em><span style="font-size: 10pt; font-family: 'Courier New'; color: black">(result.getUsername(), </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black">);</span><span style="font-size: 10pt; font-family: 'Courier New'"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black"><span>      </span>}</span><span style="font-size: 10pt; font-family: 'Courier New'"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black">}</span><span style="font-size: 10pt; font-family: 'Courier New'"><o:p></o:p></span>
</pre>
<p>De @ContextConfiguration annotatie hebben we aangepast om gebruik te maken van onze test-data.xml configuratie in plaats van de data.xml. Vervolgens laten we Spring de <em>userDao </em>injecteren.</p>
<p>Vervolgens kunnen we het gedrag van de userDao gaan specificeren.</p>
<pre>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@Before</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">public</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">void</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> mockSetup() {</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span>User testUser = </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">new</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> User(</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"Test"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">, </span><span style="font-size: 10pt; font-family: 'Courier New'; color: #2a00ff" lang="EN-US">"User"</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">);</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span><em>expect</em>(</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">userDao</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">.findBy(<em>isA</em>(String.</span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">), <em>isA</em>(String.</span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">class</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">))).andReturn(testUser).once();</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span><em>replay</em>(</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">userDao</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">);</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">}</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p> </o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: #646464" lang="EN-US">@After</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">public</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> </span><strong><span style="font-size: 10pt; font-family: 'Courier New'; color: #7f0055" lang="EN-US">void</span></strong><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"> mockRest() {</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal"><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US"><span>      </span><em>reset</em>(</span><span style="font-size: 10pt; font-family: 'Courier New'; color: #0000c0" lang="EN-US">userDao</span><span style="font-size: 10pt; font-family: 'Courier New'; color: black" lang="EN-US">);</span><span style="font-size: 10pt; font-family: 'Courier New'" lang="EN-US"><o:p></o:p></span>

<span style="font-size: 10pt; font-family: 'Courier New'; color: black">}<o:p></o:p></span></pre>
<p>Ik gebruik de @Before en @After annotaties van JUnit 4 welke respectievelijk voor en na de testcase aangeroepen worden. We laten <em>userDao</em>.findBy() nu een vooraf gedefinieerde User retourneren welke we kunnen gebruiken om de daadwerkelijk functionaliteit van de overige services te testen.<br />
Een aantal opmerkingen:</p>
<ul>
<li>Let op bij het gebruiken van scope=”prototype” voor de MockBeans.  Alle beans die hier gebruik van maken krijgen ieder een nieuwe instantie, zonder gedrag.</li>
<li>Gebruik een tearDown method om de mockobjecten te resetten. Andere beans zullen tegen dezelfde mock aanpraten met het door jouw gespecificeerde gedrag.</li>
</ul>
<p>Happy testing!</p>
<p class="MsoNormal"><span style="font-size: 12pt; line-height: 115%; font-family: 'Times New Roman','serif'"><o:p></o:p></span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2008/04/24/spring-en-easymock/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spring 2.5 &#8211; TestContext Framework</title>
		<link>http://blog.smart-java.nl/blog/index.php/2008/02/19/spring-25-testcontext-framework/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2008/02/19/spring-25-testcontext-framework/#comments</comments>
		<pubDate>Tue, 19 Feb 2008 09:10:43 +0000</pubDate>
		<dc:creator>Jethro Bakker</dc:creator>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[Tools/Frameworks]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/?p=14</guid>
		<description><![CDATA[Zoals je misschien weet zijn er in Spring 2.5 veel nieuwe annotaties geintroduceerd.  Enkele nieuwe annotaties  zijn: @Service, @Component en @Autowird.  Wat maar weinig mensen weten is dat je deze annotaties ook in kunt zetten in je testklasses. Dit wordt mogelijk gemaakt door het TestContext framework. Het TestContext framework maakt het bijvoorbeeld [...]]]></description>
			<content:encoded><![CDATA[<p style="margin-bottom: 0in">Zoals je misschien weet zijn er in Spring 2.5 veel nieuwe annotaties geintroduceerd.  Enkele nieuwe annotaties  zijn: @Service, @Component en @Autowird.  Wat maar weinig mensen weten is dat je deze annotaties ook in kunt zetten in je testklasses. Dit wordt mogelijk gemaakt door het TestContext framework. Het TestContext framework maakt het bijvoorbeeld mogelijk om de annotatie @Autowired te gebruiken in een testklasse. (Zie onderstaand voorbeeld)</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@RunWith<span style="color: #009900;">&#40;</span>SpringJUnit4ClassRunner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
@ContextConfiguration
@TransactionConfiguration<span style="color: #009900;">&#40;</span>transactionManager<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;txManager&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BlogServiceTests <span style="color: #009900;">&#123;</span>
@Autowired
<span style="color: #000000; font-weight: bold;">private</span> BlogService blogService<span style="color: #339933;">;</span>
&nbsp;
...
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Wat meteen opvalt is dat deze testklasse <strong>niet</strong> overerft van AbstractDependencyInjectionSpringContextTests of AbstractTransactionalSpringContextTests. Hiervoor in de plaats gebruik je nu de annotatie @ContextConfiguration en TransactionConfiguration.</p>
<p style="margin-bottom: 0in; font-style: normal">Deze klasse kan runnen omdat er een annotatie @RunWith is toegevoegd. Dit is een annotatie uit het JUnit4 framework. Met behulp van deze annotatie wordt JUnit op de hoogte gebracht van het Spring TestContext framework.</p>
<p style="margin-bottom: 0in; font-style: normal">Dit voorbeeld is makkelijk uit te breiden met extra annotaties zoals bijvoorbeeld:</p>
<p style="margin-bottom: 0in; font-style: normal">@DirtiesContext – Geeft aan dat een test de Spring context vervuild en zorgt ervoor dat de context opnieuw wordt opgebouwd voor de volgende test.</p>
<p style="margin-bottom: 0in; font-style: normal">@Transactional, @NotTransactional, @Rollback, @BeforeTransaction, en @AfterTransaction om transactie management te sturen.</p>
<p style="margin-bottom: 0in; font-style: normal">Een volledig voorbeeld van een test:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@org.<span style="color: #006633;">junit</span>.<span style="color: #006633;">runner</span>.<span style="color: #006633;">RunWith</span><span style="color: #009900;">&#40;</span>SpringJUnit4ClassRunner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
@ContextConfiguration
@TransactionConfiguration<span style="color: #009900;">&#40;</span>transactionManager<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;txManager&quot;</span>, defaultRollback<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>
@Transactional
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BlogServiceTests <span style="color: #009900;">&#123;</span>
&nbsp;
  @Autowired
  <span style="color: #000000; font-weight: bold;">private</span> BlogService blogService<span style="color: #339933;">;</span>
&nbsp;
  @Test
  @DirtiesContext
  @NotTransactional
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testGetMostRecent<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    List<span style="color: #339933;">&lt;</span>entry<span style="color: #339933;">&gt;</span> entries <span style="color: #339933;">=</span> blogService.<span style="color: #006633;">getMostRecentEntries</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertEquals<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, entries.<span style="color: #006633;">size</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  ....</pre></div></div>

<p style="margin-bottom: 0in; font-style: normal">Het schrijven van integratietesten wordt door het TestContext framework een stuk vereenvoudigd. Annotaties die je in je programmacode gebruikt kun je nu ook je testklasses gebruiken. Voor meer info verwijs ik je naar de referentie documentatie en de broncode van Spring 2.5. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2008/02/19/spring-25-testcontext-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JSF testen met EasyMock</title>
		<link>http://blog.smart-java.nl/blog/index.php/2008/01/15/jsf-testen-met-easymock/</link>
		<comments>http://blog.smart-java.nl/blog/index.php/2008/01/15/jsf-testen-met-easymock/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 14:33:58 +0000</pubDate>
		<dc:creator>Jan-Kees van Andel</dc:creator>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[Tools/Frameworks]]></category>
		<category><![CDATA[easymock]]></category>
		<category><![CDATA[facescontext]]></category>
		<category><![CDATA[jsf]]></category>
		<category><![CDATA[jsfunit]]></category>
		<category><![CDATA[managed bean]]></category>
		<category><![CDATA[setCurrentInstance]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[unit]]></category>

		<guid isPermaLink="false">http://blog.smart-java.nl/?p=7</guid>
		<description><![CDATA[Situatie
Je hoort vaak het argument dat JSF erg geschikt is voor unit testen. Meer dan bijvoorbeeld Struts. Ik denk dat dat erg meevalt en nog steeds erg afhankelijk is van hoe je je code programmeert.
Een veelgehoord argument is dat JSF Action methods, Converters, etc. geen dependencies hebben naar de Servlet API, waardoor deze goed in [...]]]></description>
			<content:encoded><![CDATA[<h3>Situatie</h3>
<p>Je hoort vaak het argument dat JSF erg geschikt is voor unit testen. Meer dan bijvoorbeeld Struts. Ik denk dat dat erg meevalt en nog steeds erg afhankelijk is van hoe je je code programmeert.</p>
<p>Een veelgehoord argument is dat JSF Action methods, Converters, etc. geen dependencies hebben naar de Servlet API, waardoor deze goed in isolatie te testen zijn. In veel gevallen is dit argument onzin, aangezien het grootste verschil de manier is hoe je eraan komt. In veel andere frameworks worden Servlet klassen zoals HttpServletRequest en HttpServletResponse gewoon als parameter doorgegeven aan je actions, terwijl je ze in JSF opvraagt via de FacesContext verzamelbak. De dependency blijft, behalve dat hij in JSF niet expliciet wordt meegegeven.<span id="more-7"></span></p>
<p>In mijn ervaring maakt de FacesContext het zelfs lastiger om je code goed te unit testen.</p>
<ul>
<li>Ten eerste is het een soort onzichtbare interface, want je applicatielogica maakt er gebruik van, maar het is niet gedefinieerd in de method signature. Wat gebeurt er als een bepaalde property (zoals de Locale of een session attribuut) null is? Er is geen fatsoenlijke manier om daar achter te komen (behalve eventuele JavaDoc of in de code spieken).</li>
<li>Bovendien heeft de klasse FacesContext een &#8220;leuke&#8221; eigenschap, namelijk dat de methode setFacesContext protected is. Dat wil dus zeggen dat je eerst een subklasse moet maken voordat je uberhaupt kunt gaan denken aan mocken. Bovendien moet je het maar net weten&#8230;</li>
</ul>
<h3>Voorbeeldje</h3>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> LoginPageBean <span style="color: #009900;">&#123;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> OUTCOME_LOGIN_SUCCESS <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;toHomePage&quot;</span><span style="color: #339933;">;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> username, password<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// + getter and setter         </span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> LoginService loginService<span style="color: #339933;">;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> login<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">boolean</span> loggedIn <span style="color: #339933;">=</span> loginService.<span style="color: #006633;">login</span><span style="color: #009900;">&#40;</span>username, password<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>loggedIn<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">return</span> OUTCOME_LOGIN_SUCCESS<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      FacesContext fc <span style="color: #339933;">=</span> FacesContext.<span style="color: #006633;">getCurrentInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #003399;">Locale</span> locale <span style="color: #339933;">=</span> fc.<span style="color: #006633;">getViewRoot</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getLocale</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #003399;">String</span> bundle <span style="color: #339933;">=</span> fc.<span style="color: #006633;">getApplication</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getMessageBundle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #003399;">ResourceBundle</span> rb <span style="color: #339933;">=</span> <span style="color: #003399;">ResourceBundle</span>.<span style="color: #006633;">getBundle</span><span style="color: #009900;">&#40;</span>bundle, locale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #003399;">String</span> msg <span style="color: #339933;">=</span> rb.<span style="color: #006633;">getString</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;login.msg.failure&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      fc.<span style="color: #006633;">addMessage</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">null</span>,
              <span style="color: #000000; font-weight: bold;">new</span> FacesMessage<span style="color: #009900;">&#40;</span>FacesMessage.<span style="color: #006633;">SEVERITY_ERROR</span>, msg, msg<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setLoginService<span style="color: #009900;">&#40;</span>LoginService loginService<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">loginService</span> <span style="color: #339933;">=</span> loginService<span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>         
&nbsp;
  <span style="color: #666666; font-style: italic;">// Getters and setters for username and password</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Op zich niet zulke gekke code hè? Gewoon een klasse die een service aanroept en afhankelijk van de uitkomst een foutmelding toont.</p>
<p>Op het eerste gezicht ziet het er redelijk testbaar uit. Separation of concerns is redelijk. LoginService is een interface en er zit een setter voor LoginService op de klasse, dus die kan prima gemocked worden. @runtime kan de juiste service geïnjecteerd worden met JSF&#8217;s IoC mechanisme of je gebruikt een third party plug-in zoals Spring&#8217;s <a href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/web/jsf/DelegatingVariableResolver.html" title="DelegatingVariableResolver">DelegatingVariableResolver</a>.</p>
<p>Alleen out-of-the box is het niet echt geschikt om te unit testen, door die ene FacesContext. In een unit test omgeving is de currentInstance property namelijk niet gevuld en die is essentieel voor deze klasse. We halen er namelijk de Locale uit en ook de lokatie van de properties file die de meldingen bevat. Zonder currentInstance geen groene balkjes&#8230;</p>
<h3>Oplossing met EasyMock</h3>
<p>Eens kijken of we alle problemen kunnen oplossen en een fatsoenlijke test kunnen schrijven voor deze klasse.</p>
<p>Om te beginnen maken we een subklasse van FacesContext, zodat we de currentInstance kunnen zetten.</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MockFacesContext <span style="color: #000000; font-weight: bold;">extends</span> FacesContext <span style="color: #009900;">&#123;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> setCurrentInstance<span style="color: #009900;">&#40;</span>FacesContext fc<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    FacesContext.<span style="color: #006633;">setCurrentInstance</span><span style="color: #009900;">&#40;</span>fc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>         
&nbsp;
  <span style="color: #666666; font-style: italic;">/* All abstract methods are useless here,
   * so just generate them using your
   * favorite IDE and leave the stubs.
   */</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Met deze utility klasse kunnen we de currentInstance zetten, zodat we deze straks weer netjes uit kunnen lezen.</p>
<p>Toen was er de JUnit test.</p>
<p>Let op: EasyMock ondersteunt standaard geen (abstracte) klassen zoals FacesContext, maar kan alleen interfaces mocken. Om klassen te mocke, heb je de EasyMock Class Extension nodig. Die is te downloaden van de <a href="http://www.easymock.org/Downloads.html" title="EasyMock Downloads">EasyMock downloadpagina</a>. Je hebt zowel easymock.jar en easymockclassextension.jar in je class path nodig.</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> LoginPageBeanTest <span style="color: #000000; font-weight: bold;">extends</span> TestCase <span style="color: #009900;">&#123;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> FacesContext mockFacesContext<span style="color: #339933;">;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> Application mockApplication<span style="color: #339933;">;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> UIViewRoot mockViewRoot<span style="color: #339933;">;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testLoginValidUsernameAndPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// Set up the objects.</span>
    LoginPageBean bean <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LoginPageBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    LoginService loginService <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LoginServiceMock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    bean.<span style="color: #006633;">setLoginService</span><span style="color: #009900;">&#40;</span>loginService<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    bean.<span style="color: #006633;">setUsername</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Jan-Kees&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    bean.<span style="color: #006633;">setPassword</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;secret&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// The actual method call.</span>
    <span style="color: #003399;">String</span> outcome <span style="color: #339933;">=</span> bean.<span style="color: #006633;">login</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">/* Ensure the correct outcome. Note I don't use constants in both the managed
     * bean and the unit test, because this is a better check. This is on purpose,
     * because it reminds you that the outcome has changed. If this test fails, you
     * are triggered to change your faces-config.xml files, because the navigation
     * rules may be incorrect.
     */</span>
    assertEquals<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;loginSuccess&quot;</span>, outcome<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testLoginInvalidUsernameAndPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// Set up the objects.</span>
    LoginPageBean bean <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LoginPageBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    LoginService loginService <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LoginServiceMock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    bean.<span style="color: #006633;">setLoginService</span><span style="color: #009900;">&#40;</span>loginService<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    bean.<span style="color: #006633;">setUsername</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;invalidUsername&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    bean.<span style="color: #006633;">setPassword</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;invalidPassword&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// The actual method call.</span>
    <span style="color: #003399;">String</span> outcome <span style="color: #339933;">=</span> bean.<span style="color: #006633;">login</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// Ensure the correct outcome.</span>
    assertNull<span style="color: #009900;">&#40;</span>outcome<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// Ensure all methods (in this case, only addMessage) have been called.</span>
    EasyMock.<span style="color: #006633;">verify</span><span style="color: #009900;">&#40;</span>mockFacesContext<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    EasyMock.<span style="color: #006633;">verify</span><span style="color: #009900;">&#40;</span>mockApplication<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    EasyMock.<span style="color: #006633;">verify</span><span style="color: #009900;">&#40;</span>mockViewRoot<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>         
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setUp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">/*
     * Use EasyMock to create a mock FacesContext.
     * Use org.easymock.classextension.EasyMock, not the default one.
     */</span>
    mockFacesContext <span style="color: #339933;">=</span> EasyMock.<span style="color: #006633;">createMock</span><span style="color: #009900;">&#40;</span>FacesContext.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// Make it the current instance.</span>
    FacesContextWrapper.<span style="color: #006633;">setCurrentInstance</span><span style="color: #009900;">&#40;</span>mockFacesContext<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// Create a mock Application.</span>
    mockApplication <span style="color: #339933;">=</span> EasyMock.<span style="color: #006633;">createMock</span><span style="color: #009900;">&#40;</span>Application.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">/*
     * With expect you can change the behavior of the object. In
     * this case we say: &quot;The first time you call getApplication
     * on this object, it will return the following Application&quot;.
     *
     * This call to expect is necessary, because EasyMock throws
     * Exceptions if you call a method that is not &quot;expected&quot; to be
     * called. A way to get around this is by using EasyMock.createNiceMock.
     *
     * The anyTimes() call ensures that we can call the method more
     * than once, without risking scary EasyMock Exceptions.
     *
     */</span>
    EasyMock.<span style="color: #006633;">expect</span><span style="color: #009900;">&#40;</span>mockFacesContext.<span style="color: #006633;">getApplication</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">andReturn</span><span style="color: #009900;">&#40;</span>mockApplication<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">anyTimes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// We create a UIViewRoot mock the same way as we have created the Application mock.</span>
    mockViewRoot <span style="color: #339933;">=</span> EasyMock.<span style="color: #006633;">createMock</span><span style="color: #009900;">&#40;</span>UIViewRoot.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    EasyMock.<span style="color: #006633;">expect</span><span style="color: #009900;">&#40;</span>mockFacesContext.<span style="color: #006633;">getViewRoot</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">andReturn</span><span style="color: #009900;">&#40;</span>mockViewRoot<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">anyTimes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// I've only created a Dutch MessageBundle, so I create a Dutch Locale.</span>
    <span style="color: #003399;">Locale</span> localeNL <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Locale</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;NL&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// Whenever you call getLocale on the mock UIViewRoot, return the Dutch Locale.</span>
    EasyMock.<span style="color: #006633;">expect</span><span style="color: #009900;">&#40;</span>mockViewRoot.<span style="color: #006633;">getLocale</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">andReturn</span><span style="color: #009900;">&#40;</span>localeNL<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">anyTimes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// We have mocked the MessageBundle property of the Application.</span>
    EasyMock.<span style="color: #006633;">expect</span><span style="color: #009900;">&#40;</span>mockApplication.<span style="color: #006633;">getMessageBundle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
            .<span style="color: #006633;">andReturn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;nl.ordina.jsfsample.web.resource.Messages&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">anyTimes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">/*
     * In the method under test, we call addMessage, saying:
     * &quot;I expect you to call this method, passing null as the first
     * parameter and a FacesMessage as the second parameter&quot;
     *
     * Note that I didn't say &quot;anyTimes()&quot; here. The reason is that
     * this way I am sure a message has been set. In this case, I
     * wanted to make sure the end user sees a message saying
     * something is wrong with the supplied credentials. For another
     * use case, I'd probably ignore the addMessageCall, using &quot;anyTimes()&quot;.
     */</span>
    mockFacesContext.<span style="color: #006633;">addMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span> EasyMock.<span style="color: #006633;">isNull</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, EasyMock.<span style="color: #006633;">isA</span><span style="color: #009900;">&#40;</span>FacesMessage.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">/*
     * Because addMessage is a void method, you need expectLastCall(), instead of
     * expect(some method call). expect(void method) makes your compiler unhappy.
     */</span>
    EasyMock.<span style="color: #006633;">expectLastCall</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">/*
     * Before running the tests, it is important that you replay all
     * mock objects, otherwise it doesn't work. Calling replay changes
     * the state of the mock object from preparing to working.
     */</span>
    EasyMock.<span style="color: #006633;">replay</span><span style="color: #009900;">&#40;</span>mockFacesContext<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    EasyMock.<span style="color: #006633;">replay</span><span style="color: #009900;">&#40;</span>mockApplication<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    EasyMock.<span style="color: #006633;">replay</span><span style="color: #009900;">&#40;</span>mockViewRoot<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Ten slotte</h3>
<p>Dat was een hoop boilerplate code. Vooral die setUp ziet er niet uit. Maar aan de andere kant geeft het erg veel vrijheid om je mocks te configureren. Bovendien zijn de meeste coderegels generiek voor het hele project, dus niets staat je in de weg om het weg te extraheren naar een generieke BaseTestCase.</p>
<p>Een paar dingen:</p>
<ul>
<li>Als je EasyMock voor het eerst ziet, kan het er nogal vreemd uitzien. Vooral het concept van record-replay-verify oogt misschien tricky. Maar, als je het eenmaal te pakken hebt, wordt het vanzelf een natuurlijke manier van werken.</li>
<li>Zoals hierboven ook al staat, maak aan het begin van je project een base klasse waarvan al je UI tests overerven. Die kan dan de standaard mocks creeeren. Creatie van use case specifieke mocks en properties kun je aan de subklasse overlaten. Bijvoorbeeld met een Template Method.</li>
<li>Deze methode werkt voor vrijwel alle onderdelen van de JSF applicatie. Converters, Validators, UI Components, ActionListeners, Managed Beans, Phase Listeners, etc. zijn allemaal prima te testen. Je moet alleen opletten, want het test je code niet @runtime. In een JSF applicatie zijn veel zaken die lastiger te unit testen zijn, zoals pagina&#8217;s (eigenlijk alles wat niet in Java code geschreven is). Je hebt dus nog steeds een goede integratietest nodig. JSFUnit kun je hier goed voor gebruiken. JSFUnit test ook zaken als component tree creatie. Dit zijn zaken waar unit tests niet echt geschikt voor zijn, aangezien ze teveel afhankelijk zijn van de omgeving. Voornamelijk de verschillende expressies die je in een pagina kunt opnemen zijn lastig te mocken, zeker de verschillende foutgevallen zoals nullwaarden.</li>
<li>Ten slotte is EasyMock niet echt een black box testtool. Met EasyMock worden je tests erg afhankelijk van de exacte implementatie van je code. De volgorde van statements kan bijvoorbeeld een test breken zonder dat er functioneel iets verandert. Dit kan resulteren in vrijwel onbeheersbare situaties. Maar, als dit dreigt te gebeuren, is het sowieso misschien slim om eens naar de kwaliteit van je code te kijken.</li>
</ul>
<p>Volgende keer staat JSFUnit op het menu.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.smart-java.nl/blog/index.php/2008/01/15/jsf-testen-met-easymock/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
