目次
Jspテストテクノロジー" >Jspテストテクノロジー
依存関係管理に関する苦情" >依存関係管理に関する苦情
Jsp をコンパイルする" >Jsp をコンパイルする
最終的な苦情" >最終的な苦情
结论" >结论
ホームページ Java &#&チュートリアル コンテナの外部で JSP ページをテストする方法

コンテナの外部で JSP ページをテストする方法

Aug 10, 2017 pm 03:12 PM
javascript 容器 ページ

Jspテストテクノロジー

Web アプリケーションの開発で最も面倒なことは、テストしたい場合はデプロイしなければならないことです。もちろん、すべての部分がこのようになるわけではありません。注意深く設計すれば、Java プログラムでビジネス ロジックをテストできます。アプリケーション サーバーを実行せずに、データ アクセス、インターフェイス、ストアド プロシージャをテストできます。ただし、GUI (Jsp によって生成された HTML) をテストしている場合は、テストする前にそれをデプロイする必要があります。

多くのチームは、Sellenium、Mercury、またはその他のツールを使用して、Web サーバー経由で GUI をテストします。ただし、ページの内容が同じでスタイルが変更された場合でも、テストは脆弱になります。他のチームは、Cactus を使用してこの脆弱性に対処したり、HtmlUnit や HttpUnit などの原始的なツールを使用して Web アプリケーションによって生成された HTML を監視しています。これらの問題については、別の一連のブログで説明する予定です。

この記事では、JUnit または HtmlUnit を使用して Jsp ページをテストし、コンテナから完全に分離するシンプルで簡単な技術を紹介します。これもこの技術の利点です。

必ずしもコンテナーを実行し続ける必要はなく、さらには存在し続ける必要もありません。特定の Web サーバーを選択する前に、Jsp をテストできます。

変更のたびに再デプロイする必要がないため、編集/コンパイル/テストのプロセスが速くなります。

テストファースト開発を使用して、Jsp を継続的にビルドできます。

Jsp テクノロジーがコンテナーの外で普及していない理由は、Jsp がコンテナー内で実行されるように設計されているためです。設計者は、コンテナの外で実行する可能性についてはあまり考えていませんでした。したがって、Jsp コンパイラーによって生成されるコードは、多くの場合、コンテナーによって提供される多くのコンポーネントに依存します。 JSP コードを生成するツールでも、正常にデプロイされた Web アプリケーションがすでに実行されていることを前提としています。したがって、コンテナの外で実行するには、これらのツールとコンポーネントを開発する必要があります。

依存関係管理に関する苦情

なぜ、これほど多くのフレームワークやツールの設計者は、あなたがそれらが提供する小さな世界に住むことを期待するのでしょうか? JSP をコンパイルする前に完全な Web アプリケーションを構築する必要があるのはなぜですか?なぜこれらのものをコンテナ内で実行する必要があるのでしょうか?情報の隠蔽は、10 年前から優れたソフトウェア設計の基本原則でした。私たちの業界はいつこの問題を真剣に受け止めるでしょうか?

Jsp をコンパイルする

Jsp をテストする最初のステップは、Jsp をサーブレットにコンパイルすることです。このステップを実行するには、最初に Jsp を Java 形式に変換する必要もあります。 Apache には Jasper というツールが用意されており、Jasper を呼び出して MyPage.jsp の Java 形式のソース ファイル MyPage_jsp.java を作成します。その後、お気に入りの IDE を使用して、このファイルをサーブレットにコンパイルできます。

残念ながら、Jasper はコマンド ラインで使用するように設計されていません。あるいは、まさにそのように設計されていません。ただし、Jasper にはコマンド ライン パラメーターを処理するための main 関数があり、java org.apache.jasper.JspC を呼び出すことで簡単に呼び出すことができます。ただし、Jasper は、それが実行される環境がコンテナー環境と一致していることを期待します。クラスパス上に多数の Apache Jar ファイルが存在し、Web アプリケーションの web.xml を見つけることができることを確認する必要があります。また、Web アプリケーション Jar や TLD ファイルなどが含まれる WEB-INF ディレクトリを見つけられる必要もあります。つまり、Jasper は完全な Web アプリケーションを見つけることができる必要があります。

さらに悪いことに、TOMCAT の呼び出し方法と完全に一致していない限り、特定の Jasper バージョン (私は Tomcat 5.5.20 を使用しています) にいくつかのバグがあり、生成されるコードにはいくつかのエラーが含まれます。

最初に行うことは面倒ですが、比較的簡単です。正しいディレクトリとファイル構造を作成してから、Ant で Jasper を呼び出す必要があります (クラスパスの方が制御が簡単です)。 2 番目のポイントは、それを機能させるには調査とテストが必要であるということです。以下は、正常に実行できる Ant ファイルです。 JspC への呼び出しは最後のタスクに表示されます。

<プロジェクト名="ライブラリ" デフォルト="コンパイル" basedir=".">

<プロパティ環境="env"/>

fileset>

<パス要素の場所= ${catalina.home}/shared/classes"/>

<ターゲット名="clean">

< ;classpath refid="compile.classpath"/>

&&lt;ターゲット名= "jar"依存= "コンパイル"&gt;

&lt; mkdir dir = "$ {build.jar.home}"/&gt;

&lt ;jar jarfile="${build.jar.home}/application.jar" basedir="${build.classes.home}" include="**/application/**/*.class" />

<コピー先dir="${ビルド。 war.home}">

< ;jar jarfile="${dist.home}/${app.name}.war" basedir="${build.war.home}"/>

<クラスパス>

<名前=を含める"*.jar"/>

< include name="*.jar"/>

>

includes= "**/jsp/**/*.class"

もちろん、${build.war の下にすべての標準ファイルとディレクトリが必要です。 home} を実行して、機能することを確認します。 Jsp でカスタム タグを使用する場合は、対応するすべての TLD ファイルが TLD ディレクトリにあることも確認してください。

Jspc のコマンド ラインは、Tomcat が提供する JspC Ant タスクを使用するのではなく、ant ファイル内で呼び出されることに注意してください。カスタムタグがあると正しく動作しないことがわかったためです。おそらく私が混乱しているか、JspC に実際にバグがあるのか​​もしれません。しかし、Jasper に正しいコードを生成させる唯一の方法は、Jasper をコマンド ラインから呼び出し、Jsp ファイル パスをコマンド ライン引数として明示的に渡すことです。 Ant タスクに依存するか、コマンド ラインを使用してすべての Web アプリケーションで Jsps を検索してコンパイルすると、不正なコードが生成されます。 (このブログを参照してください)

Java ファイルを取得したので、それを分析しましょう。まずは、以下のJspファイルをご覧ください。

<%@ page import="com.objectmentor.library.utils.DateUtil" %>

<%@ page import="com.objectmentor.library.web. controller.patrons.LoanRecord" %>

<%@ page import="java.util.List" %>

<%

List loanRecords = (リスト) request .getAttribute("loanRecords");

if (loanRecords.size() > 0) {

%>

lt;/th>

&lt;%

for(int i = 0; i&lt; loanrecords.size(); i ++){

">

}

%>

期限

罰金
<%=loanRecord。 id%>

<%=loanRecord.title%>

<%=DateUtil.dateToString(loanRecord.dueDate)%>

<%

}

%>

次は Jasper が生成した代価です

package com.objectmentor.library.jsp.WEB_002dINF.pages.patrons.books;

import javax.servlet.*;

javax.servletをインポートする.http.*;

import javax.servlet.jsp.*;

import com.objectmentor.library.utils.DateUtil;

import com.objectmentor.library.web.controller.patrons。 LoanRecord;

import java.util.List;

public Final class loanRecords_jsp extends org.apache.jasper.runtime.HttpJspBase

実装 またはg.apache.jasper.runtime。 JspSourceDependent {

private static java.util.List _jspx_dependants;

public Object getDependants() {

return _jspx_dependants;

}

public void _jspService(HttpServletRequest request, HttpServletResponse response)

throws java.io.IOException、ServletException {

JspFactory _jspxFactory = null;

PageContext pageContext = null;

HttpSession session = null;

サーブレットコンテキスト アプリケーション = null;

ServletConfig config = null;

JspWriter out = null;

オブジェクトページ = this;

JspWriter _jspx_out = null;

PageContext _jspx_page_context = null;

試してください {

_jspxFactory = JspFactory.getDefaultFactory();

response.setContentType("text/html");

pageContext = _jspxFactory.getPageContext(this, リクエスト, レスポンス,

null、true、8192、true);

_jspx_page_context = pageContext;

application = pageContext.getServletContext();

config = pageContext.getServletConfig();

session = pageContext.getSession();

out = pageContext.getOut();

_jspx_out = out;

out.write( '/n');

アウト。 write('/n');

out.write('/n');

List loanRecords = (List) request.getAttribute("loanRecords");

if (loanRecords.size() > 0) {

out.write("/n");

out.write("< table class=/"list/" id=/"loanRecords/">/n");

out.write(" /n");

out.write("

ID/n");

out.write("

タイトル/n");

out.write("> ;/th>/n ");

out.write(" /n");

out.write(" ");

for (int i = 0;私は<ローンレコード.サイズ(); i++) {

LoanRecord loanRecord = (LoanRecord) launchRecords.get(i);

out.write("/n");

out.write("

out.print(i%2==0?"even":"odd");

out.write("/">/n");

out.write(" ");

out.print(loanRecord.id );

out.write("/n");

out.write(" /n");

out.write (" ");

out.print(loanRecord.title);

out.write("/n");

アウト。 write(" /n");

out.write(" ");

out.print( DateUtil.dateToString(loanRecord .dueDate));

out.write("/n");

out.write(" /n");

out.write(" ");

out.print(loanRecord.fine.toString());

out.write("/n");

out.write(" /n");

out.write(" /n");

out.write(" ");

}

out.write("/n") ;

アウト。 write("/n");

}

} catch (Throwable t) {

if (! (t instanceof SkipPageException)){

out = _jspx_out;

if (out != null && out.getBufferSize() != 0)

out.clearBuffer() ;

if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);

}

} ついに {

if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context );

}

}

}

最終的な苦情

なぜこのクラスが最終と宣言される必要があるのですか?テスト スタブの派生クラスを作成したい場合はどうすればよいですか?生成されたクラスが非常に不快で、オーバーライドすることさえできないのはなぜでしょうか?

このコードを注意深く読むと、このサーブレット インスタンスを使用するには HttpServletRequest と HttpServletResponse のインスタンスが必要であることがわかります。

さらに注意深く調べると、サーブレットはすべての HTML を JspWriter のインスタンスに書き込み、JspWriter は PageContext から取得されることがわかります。このすべての HTML を保持する JspWriter のモックアップ バージョンを作成し、次にモック JspWriter を送出する PageContext のモックアップ バージョンを作成できれば、テストでこの HTML にアクセスできるようになります。

幸いなことに、Tomcat の設計者は、JspWriter の作成を JspFactory のファクトリー クラスに組み込みました。そして、このファクトリー クラスはオーバーライドできます。これは、サーブレットを変更せずに、サーブレット内で独自の JspWriter クラスを取得できることを意味します。必要なのは次のコードだけです。

class MockJspFactory extends JspFactory {

public PageContext getPageContext(Servlet servlet, ServletRequest servletRequest, letResponse servletResponse、文字列 string、ブール値 b、int i、ブール値 b1) {

return new MockPageContext(new MockJspWriter());

}

public void releasePageContext( PageContext pageContext) {

}

public JspEngineInfo getEngineInfo() {

return null;

}

}

さて、私たちは必要なのはモック Jspwriter です。プレゼンテーションを簡単にするために、次のものを使用しました:

MockJspWriter

package com.objectmentor.library.web.framework.mocks;

javax.servletをインポートします。 jsp.JspWriter;

import java.io.IOException;

public class MockJspWriter extends JspWriter {

プライベート StringBuffer が送信されたコンテンツ;

public MockJspWriter(intbufferSize, boolean autoFlush) {

super(bufferSize, autoFlush);

submittedContent = new StringBuffer();

}

public String getContent() {

return submitContent.toString();

}

public void print(String arg0) throws IOException {

submittedContent.append(arg0);

}

public void write(char[] 、int arg1、int arg2) IOException をスローします {

for (int i=0; i

submittedContent.append(String.valueOf(arg0[arg1++]));

}

public void write(String content) throws IOException {

submittedContent.append(content);

}

// 面白くないことがたくさんあるメソッドは省略されました。 私はそれらを与えただけです

// 実装を縮退します。 (例: {})

}

不要关心那珂我省略掉的未实现方法としては、私たちのテストを実行するために必要なだけの方法で十分であると考えています。以下の場合は、その退化を使用するだけです。

同様のメソッドを使用して、MockPageContext、MockHttpServletRequest、および MockHttpServletResponse クラスを構築できます。

MockPageContext

package com.objectmentor.library.web.framework.mocks;

import javax.servlet.*;

import javax.サーブレット.http.*;

import javax.servlet.jsp.*;

import java.io.IOException;

import java.util.Enumeration;

public class MockPageContext extends PageContext {

プライベート最終JspWriter出力;

プライベートHttpServletRequestリクエスト;

パブリックMockPageContext(JspWriter out) {

this.out = out;

request = new MockHttpServletRequest();

}

getOut( ) {

出てください;

}

public ServletRequest getRequest() {

return request;

}

// 多くの縮退関数が省略されました。

}

MockHttpServletRequest

パッケージ com.objectmentor.library.web.framework.mocks;

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

import主要;

import java.util.*;

public class MockHttpServletRequestimplements HttpServletRequest {

private Stリングメソッド;

private String contextPath;

private String requestURI;

private HttpSession session = new MockHttpSession();

private Map パラメータ = new HashMap();

プライベートマップ属性 = 新しいHashMap();

public MockHttpServletRequest(Stringメソッド, String contextPath,

文字列 requestURI) {

super();

this .method = メソッド;

this.contextPath = contextPath;

this.requestURI = requestURI;

}

public MockHttpServletRequest() {

this("GET");

}

public MockHttpServletRequest(Stringメソッド) {

this(メソッド, "/ライブラリ", "/Library/foo/bar.jsp");

}

public String getContextPath() {

contextPath を返す;

}

public String getMethod() {

returnメソッド;

}

public String getRequestURI( ) {

return requestURI;

}

public String getServletPath() {

return requestURI.substring(getContextPath().length ());

}

public HttpSession getSession() {

リターンセッション;

}

public HttpSession getSession (boolean arg0) {

return session;

}

public Object getAttribute(String 0) {

returnattributs.get( arg0);

}

public String getParameter(String arg0) {

return (文字列)parameters.get(arg0);

}

public Map getParameterMap() {

returnパラメータ;

}

public Enumeration getParameterNames( ) {

return null;

}

public void setSession(HttpSession session) {

this.session = セッション;

}

public void setParameter(String s, String s1) {

parameters.put(s, s1);

}

public void setAttribute(String name, Object value) {

attributes.put(name, value);

}

// 多くの縮退メソッドが省略されました。

}

MockHttpServletResponse

package com.objectmentor.library.web.framework.mocks;

javaxをインポートする.servlet.ServletOutputStream;

import javax.servlet.http.*;

import java.io.*;

import java.util.Locale;

公開クラスMockHttpServletResponse は HttpServletResponse を実装します {

// すべての関数は縮退するように実装されています。

}

loanRecords_jsp のサーブレットの例を作成できるそして、调用を開始します! 私たちの唯一の赋试用例は次のとおりです:

<br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  public void testSimpleTest() throws Exception {
ログイン後にコピー
    MockJspWriter jspWriter = new MockJspWriter();
ログイン後にコピー
    MockPageContext pageContext = new MockPageContext(jspWriter);
ログイン後にコピー
    JspFactory.setDefaultFactory(new MockJspFactory(pageContext));
ログイン後にコピー
    HttpJspBase jspPage = new loanRecords_jsp();
ログイン後にコピー
ログイン後にコピー
    HttpServletRequest request = new MockHttpServletRequest();
ログイン後にコピー
    HttpServletResponse response = new MockHttpServletResponse();
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    jspPage._jspInit();
ログイン後にコピー
ログイン後にコピー
    jspPage._jspService(request, response);
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    assertEquals("", jspWriter.getContent());
ログイン後にコピー
  }
ログイン後にコピー
ログイン後にコピー
<br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

就像预期的一样,测试失败了。这是因为还有些内容还没补充上,不过所剩无多。如果你仔细的看过Jsp文件,你就会发现它调用了request.getAttribute(“loanRecords”)并且期望返回一个List。但因为目前的测试并未为这样的属性赋值,从而导致了代码抛出了异常。

要想成功让servlet输出HTML,我们还需要加载这个属性。然后,我们就可以使用HtmlUnit来解析此HTML并且编写相应的单元测试。

HtmlUnit非常的容易使用,尤其是在测试所产生的像是本例这样的web pages上。我这里还有篇文章详细的介绍了它。

下面就是最终测试加载属性的测试,它通过htmlunit来检测HTML,并且做出正确的判断:

<br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
package com.objectmentor.library.jspTest.books.patrons.books;
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
import com.gargoylesoftware.htmlunit.*;
ログイン後にコピー
import com.gargoylesoftware.htmlunit.html.*;
ログイン後にコピー
import com.objectmentor.library.jsp.WEB_002dINF.pages.patrons.books.loanRecords_jsp;
ログイン後にコピー
import com.objectmentor.library.utils.*;
ログイン後にコピー
import com.objectmentor.library.web.controller.patrons.LoanRecord;
ログイン後にコピー
import com.objectmentor.library.web.framework.mocks.*;
ログイン後にコピー
import junit.framework.TestCase;
ログイン後にコピー
import org.apache.jasper.runtime.HttpJspBase;
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
import javax.servlet.*;
ログイン後にコピー
import javax.servlet.http.*;
ログイン後にコピー
import javax.servlet.jsp.*;
ログイン後にコピー
import java.util.*;
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
public class LoanRecordsJspTest extends TestCase {
ログイン後にコピー
  private MockPageContext pageContext;
ログイン後にコピー
  private MockJspWriter jspWriter;
ログイン後にコピー
  private JspFactory mockFactory;
ログイン後にコピー
  private MockHttpServletResponse response;
ログイン後にコピー
  private MockHttpServletRequest request;
ログイン後にコピー
  private WebClient webClient;
ログイン後にコピー
  private TopLevelWindow dummyWindow;
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  protected void setUp() throws Exception {
ログイン後にコピー
    jspWriter = new MockJspWriter();
ログイン後にコピー
    pageContext = new MockPageContext(jspWriter);
ログイン後にコピー
    mockFactory = new MockJspFactory(pageContext);
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    JspFactory.setDefaultFactory(mockFactory);
ログイン後にコピー
    response = new MockHttpServletResponse();
ログイン後にコピー
    request = new MockHttpServletRequest();
ログイン後にコピー
    webClient = new WebClient();
ログイン後にコピー
    webClient.setJavaScriptEnabled(false);
ログイン後にコピー
    dummyWindow = new TopLevelWindow("", webClient);
ログイン後にコピー
  }
ログイン後にコピー
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  public void testLoanRecordsPageGeneratesAppropriateTableRows() throws Exception {
ログイン後にコピー
    HttpJspBase jspPage = new loanRecords_jsp();
ログイン後にコピー
ログイン後にコピー
    jspPage._jspInit();
ログイン後にコピー
ログイン後にコピー
 <br/>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    List<LoanRecord> loanRecords = new ArrayList<LoanRecord>();<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">    addLoanRecord(loanRecords,
ログイン後にコピー
ログイン後にコピー
                  "99",
ログイン後にコピー
                  "Empire",
ログイン後にコピー
                  DateUtil.dateFromString("2/11/2007"),
ログイン後にコピー
                  new Money(4200));
ログイン後にコピー
    addLoanRecord(loanRecords,
ログイン後にコピー
                  "98",
ログイン後にコピー
                  "Orbitsville",
ログイン後にコピー
                  DateUtil.dateFromString("2/12/2007"),
ログイン後にコピー
                  new Money(5200));
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    request.setAttribute("loanRecords", loanRecords);
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    jspPage._jspService(request, response);
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    StringWebResponse stringWebResponse = new StringWebResponse(jspWriter.getContent());
ログイン後にコピー
    HtmlPage page = HTMLParser.parse(stringWebResponse, dummyWindow);
ログイン後にコピー
    HtmlElement html = page.getDocumentElement();
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    HtmlTable table = (HtmlTable) html.getHtmlElementById("loanRecords");
ログイン後にコピー
    List<HtmlTableRow> rows = table.getHtmlElementsByTagName("tr");
ログイン後にコピー
    assertEquals(3, rows.size());
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    assertEquals("even", classOfElement(rows.get(1)));
ログイン後にコピー
    assertEquals("odd", classOfElement(rows.get(2)));
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    List<HtmlTableDataCell> firstRowCells = rows.get(1).getCells();
ログイン後にコピー
    assertEquals(4, firstRowCells.size());
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    List<HtmlTableDataCell> secondRowCells = rows.get(2).getCells();
ログイン後にコピー
    assertEquals(4, secondRowCells.size());
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    assertLoanRecordRowEquals("99", "Empire", "02/11/2007", "$42.00", firstRowCells);
ログイン後にコピー
    assertLoanRecordRowEquals("98", "Orbitsville", "02/12/2007", "$52.00", secondRowCells);
ログイン後にコピー
  }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  private String classOfElement(HtmlTableRow firstDataRow) {return firstDataRow.getAttributeValue("class");}
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  private void assertLoanRecordRowEquals(String id, String title, String dueDate, String fine, List<HtmlTableDataCell> rowCells) {
ログイン後にコピー
    assertEquals(id, rowCells.get(0).asText());
ログイン後にコピー
    assertEquals(title, rowCells.get(1).asText());
ログイン後にコピー
    assertEquals(dueDate, rowCells.get(2).asText());
ログイン後にコピー
    assertEquals(fine, rowCells.get(3).asText());
ログイン後にコピー
  }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  private void addLoanRecord(List<LoanRecord> loanRecords, String id, String title, Date dueDate, Money fine) {
ログイン後にコピー
    LoanRecord loanRecord = new LoanRecord();
ログイン後にコピー
    loanRecord.id = id;
ログイン後にコピー
    loanRecord.title = title;
ログイン後にコピー
    loanRecord.dueDate = dueDate;
ログイン後にコピー
    loanRecord.fine = fine;
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    loanRecords.add(loanRecord);
ログイン後にコピー
  }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  private class MockJspFactory extends JspFactory {
ログイン後にコピー
    private PageContext pageContext;
ログイン後にコピー
    public MockJspFactory(PageContext pageContext) {
ログイン後にコピー
      this.pageContext = pageContext;
ログイン後にコピー
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    public PageContext getPageContext(Servlet servlet, ServletRequest servletRequest, ServletResponse servletResponse, String string, boolean b, int i, boolean b1) {
ログイン後にコピー
      return pageContext;
ログイン後にコピー
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    public void releasePageContext(PageContext pageContext) {
ログイン後にコピー
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 <br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
    public JspEngineInfo getEngineInfo() {
ログイン後にコピー
      return null;
ログイン後にコピー
    }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  }
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
}
ログイン後にコピー

<br>
ログイン後にコピー

<span style="font-size: 9pt;">上述的测试确保了所生成的HTML中表格中的每一行都具有正确的内容。这项测试确实能够测出是否存在这样的表格,并且判断出是否表格的每一行是按照正确的顺序来展现的。同时,它也确保了每一行的相应style。测试忽略了此外的表单以及语法部分。</span>

结论

这篇发表在此的技术能够用来测试几乎所有目前我们所见过的web页面,并且脱离容器,也无需web server的运行。相对来说,它也比较容易去设置,并且非常易于扩展。有了它,你就可以快速的进行编辑、编译、测试的周期性迭代,并且你也能遵循测试驱动开发的原则了。<br>

(原文链接网址: http://blog.objectmentor.com/articles/category/testing-guis; Robert C. Martin的英文blog网址: http://blog.objectmentor.com/ 

作者简介:Robert C. Martin是Object Mentor公司总裁,面向对象设计、模式、UML、敏捷方法学和极限编程领域内的资深顾问。他不仅是Jolt获奖图书《敏捷软件开发:原则、模式与实践》(中文版)(《敏捷软件开发》(英文影印版))的作者,还是畅销书Designing Object-Oriented C++ Applications Using the Booch Method的作者。Martin是Pattern Languages of Program Design 3和More C++ Gems的主编,并与James Newkirk合著了XP in Practice。他是国际程序员大会上著名的发言人,并在C++ Report杂志担任过4年的编辑。

以上がコンテナの外部で JSP ページをテストする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Wordでページをコピーする方法 Wordでページをコピーする方法 Feb 20, 2024 am 10:09 AM

Microsoft Word でページをコピーし、書式設定をそのまま維持したいですか? Word でページを複製すると、特定の文書レイアウトまたは形式のコピーを複数作成する場合に時間の節約に役立つため、これは賢明なアイデアです。このガイドでは、テンプレートを作成する場合でも、文書内の特定のページをコピーする場合でも、Word でページをコピーする手順を段階的に説明します。これらの簡単な手順は、最初から始めなくてもページを簡単に再作成できるように設計されています。 Microsoft Word でページをコピーする必要があるのですか? Word でページをコピーすることが非常に有益である理由はいくつかあります。 特定のレイアウトまたは形式の文書をコピーしたい場合。ページ全体を最初から再作成するのとは異なります

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

Web ページをすばやく更新するにはどうすればよいですか? Web ページをすばやく更新するにはどうすればよいですか? Feb 18, 2024 pm 01:14 PM

ネットワークを日常的に使用する中でページの更新は頻繁に行われますが、Web ページにアクセスすると、Web ページが読み込まれない、表示が異常になるなどの問題が発生することがあります。現時点では、通常、問題を解決するためにページを更新することを選択しますが、ページを素早く更新するにはどうすればよいでしょうか?ページ更新のショートカット キーについて説明します。ページ更新ショートカットキーは、キーボード操作で現在のWebページを素早く更新する方法です。オペレーティング システムやブラウザが異なると、ページを更新するためのショートカット キーが異なる場合があります。以下では一般的な W を使用します。

ファーウェイ、Inspur、その他の部門が共同で設立したオープンソースのコンテナミラーリングセンターであるAtomHubは、正式に公開テストを開始し、国内サービスを安定してダウンロードできると発表した。 ファーウェイ、Inspur、その他の部門が共同で設立したオープンソースのコンテナミラーリングセンターであるAtomHubは、正式に公開テストを開始し、国内サービスを安定してダウンロードできると発表した。 Jan 02, 2024 pm 03:54 PM

ファーウェイの公式ニュースによると、「開発者のためのすべて」をテーマとしたオープン・アトミック・デベロッパー・カンファレンスが12月16日から17日までの2日間、無錫で開催された。このカンファレンスは、オープン・アトミック・オープンソース財団、ファーウェイ、 Inspur.、DaoCloud、Xieyun、Qingyun、Hurricane Engine、OpenSDV Open Source Alliance、openEuler コミュニティ、OpenCloudOS コミュニティ、その他のメンバー ユニットが共同で AtomHub Trusted Mirror Center の構築を開始し、正式に公開テストが開始されました。 AtomHub は、共同構築、共同ガバナンス、共有の概念を遵守し、オープンソース組織と開発者に中立的でオープンで共同構築された信頼できるオープンソース コンテナ ミラー センターを提供することを目指しています。 DockerHub などのイメージ ウェアハウスの不安定性と制御不能性を考慮して、

3 秒でページジャンプを実装する方法: PHP プログラミングガイド 3 秒でページジャンプを実装する方法: PHP プログラミングガイド Mar 25, 2024 am 10:42 AM

タイトル: 3秒でできるページジャンプの実装方法: PHPプログラミングガイド Web開発においてページジャンプは一般的な操作ですが、通常はHTMLやJavaScriptのメソッド内のメタタグを使ってページにジャンプします。ただし、特定のケースでは、サーバー側でページ ジャンプを実行する必要があります。この記事では、PHPプログラミングを使用して、3秒以内に指定したページに自動でジャンプする機能を実装する方法と、具体的なコード例を紹介します。 PHP を使用したページジャンプの基本原理 PHP は一種の

LaravelページでCSSが正しく表示されない場合の対処方法 LaravelページでCSSが正しく表示されない場合の対処方法 Mar 10, 2024 am 11:33 AM

「CSS を正しく表示できない Laravel ページを処理する方法、特定のコード例が必要」 Laravel フレームワークを使用して Web アプリケーションを開発する場合、ページで CSS スタイルを正しく表示できず、ページのレンダリングが異常になるという問題が発生することがあります。スタイル。ユーザー エクスペリエンスに影響します。この記事では、Laravel ページで CSS が正しく表示されない場合に対処するいくつかの方法を紹介し、開発者がこの一般的な問題を解決するのに役立つ具体的なコード例を示します。 1. ファイルパスを確認する まずCSSファイルのパスを確認します。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

See all articles