<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC
  "-//Apache Software Foundation//DTD XDOC 1.0//EN"
  "http://maven.apache.org/dtd/xdoc_1_0.dtd">

<document>
  <properties>
    <title>ドメインのテストと実装 - DAO Test &amp; Implement</title>
    <author email="kurokkie@users.sourceforge.jp">kurokkie</author>
  </properties>
  <body>
    <section name="ドメインのテストと実装">
      <p>
ドメインのテストと実装を作成します。ここでもデータアクセスオブジェクトと同様、
<strong>テストファースト</strong> による開発プロセスを採用しています。
      </p>
    </section>
    <section name="テストケース">
      <p>
ドメインに作成した
<a href="apidocs/org/unitedfront2/domain/communication/Blog.html"><code>Blog</code></a> 、
<a href="apidocs/org/unitedfront2/domain/communication/BlogEntry.html"><code>BlogEntry</code></a> 、
<a href="apidocs/org/unitedfront2/domain/communication/BlogTable.html"><code>BlogTable</code></a> 、
<a href="apidocs/org/unitedfront2/domain/communication/BlogEntryTable.html"><code>BlogEntryTable</code></a>
のテストケースを作成します。複雑な検証ロジックがある場合は検証クラス
<a href="apidocs/org/unitedfront2/domain/communication/BlogValidator.html"><code>BlogValidator</code></a>
のテストケースも作成します。ここでは <code>BlogTest</code> と <code>BlogTableTest</code> を紹介し
ます。完全なソースは
<a href="xref-test/org/unitedfront2/domain/communication/BlogTest.html"><code>BlogTest</code> のソースコード</a> 、
<a href="xref-test/org/unitedfront2/domain/communication/BlogEntryTest.html"><code>BlogEntryTest</code> のソースコード</a> 、
<a href="xref-test/org/unitedfront2/domain/communication/BlogTableTest.html"><code>BlogTableTest</code> のソースコード</a> 、
<a href="xref-test/org/unitedfront2/domain/communication/BlogEntryTableTest.html"><code>BlogEntryTableTest</code> のソースコード</a>
を参照ください。
      </p>
      <subsection name="BlogTest">
        <p>
<code>BlogTest</code> では、<code>post</code> および <code>store</code> メソッドに対する
テストケースを紹介します。<code>store</code> メソッドでは、登録に成功、登録に失敗、更新に成功、更新に
失敗の４ケースをテストする必要があります。
        </p>
<pre name="code" class="java">
public class BlogTest extends AbstractTransactionalTestsWithInitialData {

    @Autowired BlogTable blogTable;

    @Test
    public void testStore登録() throws BlogCodeUsedByOtherException {
        Blog blog = createBlog();
        blog.store();
        Blog actual = blogTable.find(blog.getId());
        Assert.assertEquals(blog, actual);
    }

    @Test(expected=BlogCodeUsedByOtherException.class)
    public void testStore登録を試みるがコードが重複()
        throws BlogCodeUsedByOtherException {
        Blog blog = createBlog();
        blog.store();
        Blog blog2 = blogTable.prototype(blog);
        blog2.setId(null);
        blog2.store();
    }

    @Test
    public void testStore更新() throws BlogCodeUsedByOtherException {
        Blog blog = createBlog();
        blog.store();
        blog.setCode("new_" + blog.getCode());
        blog.getReadAccessControl().changeTo(AccessControlType.FRIEND_ONLY);
        blog.store();
        Blog actual = blogTable.find(blog.getId());
        Assert.assertEquals(blog, actual);
    }

    @Test(expected=BlogCodeUsedByOtherException.class)
    public void testStore更新を試みるがコードが重複()
        throws BlogCodeUsedByOtherException {
        Blog blog = createBlog();
        blog.store();
        Blog blog2 = blogTable.prototype(blog);
        blog2.setId(null);
        blog2.setCode(blog2.getCode() + "2");
        blog2.store();
        blog2.setCode(blog.getCode());
        blog2.store();
    }

    @Test
    public void testPost() throws BlogCodeUsedByOtherException {
        Blog blog = createBlog();
        blog.store();
        BlogEntry blogEntry = createBlogEntry(blog.getReadAccessControl(),
                blog.getWriteAccessControl());

        blog.retrieveBlogEntries(0, 1);
        Assert.assertSame(0, blog.getBlogEntries().size());
        blog.post(blogEntry);
        blog.retrieveBlogEntries(0, 1);
        Assert.assertSame(1, blog.getBlogEntries().size());
        Assert.assertEquals(blogEntry, blog.getBlogEntries().get(0));
    }

    // other test methods

    private Blog createBlog() {
        // テスト用のブログを生成
    }

    private BlogEntry createBlogEntry(AccessControl readAccessControl,
            AccessControl writeAccessControl) {
        // テスト用のブログ記事を生成
    }
}
</pre>
      </subsection>
      <subsection name="BlogTableTest">
        <p>
<a href="apidocs/org/unitedfront2/domain/communication/BlogTable.html"><code>BlogTable</code></a>
は <a href="apidocs/org/unitedfront2/domain/SimpleTableModule.html"><code>SimpleTableModule</code></a>
を継承したクラスであるため、それに対応する <code>BlogTableTest</code> は <a href="xref-test/org/unitedfront2/test/TableModuleTestCaseSupport.html"><code>TableModuleTestCaseSupport</code></a>
を継承することで基本的なテストケースを再利用できます。<a href="apidocs/org/unitedfront2/domain/communication/BlogTable.html"><code>BlogTable</code></a>
は独自メソッド <code>findByCode</code> を持っていますが、このメソッドは単にデータアクセスオブジェクトに
処理を委譲しているだけですので、テストケースは作成していません。
        </p>
<pre name="code" class="java">
public class BlogTableTest extends TableModuleTestCaseSupport&lt;Blog&gt; {

    @Autowired private BlogTable blogTable;

    @Override
    protected Blog createDomain() {
        // テスト用のブログを生成
    }

    @Override
    protected SimpleDomainsSupport&lt;Blog&gt; getTableModule() {
        return blogTable;
    }

    @Override
    protected SimpleFindable&lt;Blog&gt; getSimpleDao() {
        return blogTable.getSimpleDao();
    }
}
</pre>
      </subsection>
    </section>
    <section name="ドメインの実装">
      <p>
ドメイン設計時に実装を保留した箇所を実装します。全てのテストに合格すれば、実装完了です。ドメインの完全なソー
スコードは <a href="xref/org/unitedfront2/domain/communication/Blog.html"><code>Blog</code> のソースコード</a> 、
<a href="xref/org/unitedfront2/domain/communication/BlogEntry.html"><code>BlogEntry</code> のソースコード</a> 、
<a href="xref/org/unitedfront2/domain/communication/BlogTable.html"><code>BlogTable</code> のソースコード</a> 、
<a href="xref/org/unitedfront2/domain/communication/BlogEntryTable.html"><code>BlogEntryTable</code> のソースコード</a>
を参照ください。
      </p>
      <subsection name="Blog">
        <p>
<a href="apidocs/org/unitedfront2/domain/communication/Blog.html"><code>Blog</code></a>
の <code>store</code> メソッドでは、コードが重複しないことを確認してから永続化処理を行っています。また、
<code>delete</code> メソッドでは、関連するブログ記事が存在しないことを確認してから削除処理を行っていま
す。
        </p>
<pre name="code" class="java">
public class Blog ... {

    // ...

    @Override
    public void store() throws BlogCodeUsedByOtherException {
        Blog foundByCode = blogDao.findByCode(code);
        if (foundByCode != null &amp;&amp; !foundByCode.identify(this)) {
            String message = "The code '" + code
                + "' has already been used by other.";
            logger.warn(message);
            throw new BlogCodeUsedByOtherException(message);
        }
        if (this.id == null) {
            blogDao.register(this);
        } else {
            blogDao.update(this);
        }
    }

    @Override
    public void delete() throws BlogEntryExistException {
        int count = blogDao.countBlogEntry(id);
        if (count > 0) {
            String message = "The blog [ID=" + id + "] has " + count
                + " entries.";
            logger.warn(message);
            throw new BlogEntryExistException(message);
        }
        blogDao.delete(id);
    }

    public void post(BlogEntry blogEntry) {
        blogEntry.store();
        blogDao.registerBlogEntry(id, blogEntry.getId());
    }

    public void retrieveEntries(int no, int num) {
        entries = blogDao.findBlogEntries(id, no, num);
    }

    // ...
}
</pre>
      </subsection>
      <subsection name="BlogEntry">
        <p>
<a href="apidocs/org/unitedfront2/domain/communication/BlogEntry.html"><code>BlogEntry</code></a>
の <code>delete</code> メソッドでは、関連する全てのコメントを削除しています。
        </p>
<pre name="code" class="java">
public class BlogEntry ... {

    // ...

    @Override
    public void store() {
        try {
            entry.store();
        } catch (MessageCodeUsedByOtherException e) {
            // 起こらない。記事のコードは自動生成される。
            logger.error(e);
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void delete() {
        entry.delete();
    }

    public void retrieveComments() {
        comments = blogDao.findComments(getId());
    }

    public void post(Comment comment) {
        comment.store();
        blogDao.registerComment(getId(), comment.getId());
    }

    // ...
}
</pre>
      </subsection>
    </section>
    <section name="Bean 定義">
      <p>
最後に <a href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/resources/applicationContext-dao.xml?root=unitedfront2&amp;view=markup">applicationContext-dao.xml</a>
および <a href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/resources/applicationContext-domain.xml?root=unitedfront2&amp;view=markup">applicationContext-domain.xml</a>
に作成したデータアクセスオブジェクトおよびドメインクラスを記載して完了です。未定義の <a href="apidocs/org/unitedfront2/domain/communication/BlogValidator.html"><code>BlogValidator</code></a>
は <a href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/resources/applicationContext-domain.xml?root=unitedfront2&amp;view=markup">applicationContext-domain.xml</a>
に追記します。
      </p>
<pre name="code" class="xml">
&lt;bean id="communication.blogValidator"
    class="org.unitedfront2.domain.communication.BlogValidator"&gt;
  &lt;property name="blogTable" ref="communication.blogTable"/&gt;
&lt;/bean&gt;
</pre>

<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shCore.js"></script>
<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shBrushJava.js"></script>
<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shBrushXml.js"></script>
<script type="text/javascript">
dp.SyntaxHighlighter.ClipboardSwf = 'js/dp.SyntaxHighlighter/Scripts/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('code');
</script>

<script type="text/javascript">
var ID='100354378-sbs_dmTestImpl';
var AD=1;
var FRAME=0;
</script>
<script src="http://j1.ax.xrea.com/l.j?id=100354378" type="text/javascript"></script>
<noscript>
<a href="http://w1.ax.xrea.com/c.f?id=100354378" target="_blank"><img src="http://w1.ax.xrea.com/l.f?id=100354378&amp;url=X" alt="AX" border="0"/></a>
</noscript>

    </section>
  </body>
</document>
