2009年7月27日
测试1:测试网页是否存在:
要测试一個网页是否存在,只要简单的通过WebConversation的getResponse()方法即可,例如:
WebConversation webConversation = new WebConversation();
webConversation.getResponse(
牋牋牋牋牋牋 "http://localhost:8080/httpUnit/");
如果找不到网页,則會引发HttpNotFoundException,由于不是断言错误,所以这会在JUnit中产生一個Error。
测试2:Get、Post:
您可以分別使用GetMethodWebRequest或PostMethodWebRequest來发出Get或Post请求,例如:
WebConversation webConversation = new WebConversation();
WebRequest request =new GetMethodWebRequest("http://localhost:8080/httpUnit/");
WebResponse response =webConversation.getResponse(request);
要在请求中加上參數,可以使用setParamter()方法,例如:
request.setParameter("username","taobaoge");
测试3:取得表格信息:
您可以从WebResponse中取得相关的HTML信息,假设网页中有如下这样的一个表格:
| 书籍名称 | 设计模式(Design Pattern) |
| 软件版本 | 无 |
| 书籍版次 | 第二版 |
| 修改时间 | 2004/12/26 |
下面的程序演示如何取得表格相关信息进行测试:
WebConversation webConversation = new WebConversation();
WebResponse response = webConversation.getResponse("http://localhost:8080/httpUnit/tableTest.jsp");
WebTable webTable = response.getTables()[0];
assertEquals(2, webTable.getColumnCount());
TableCell cell = webTable.getTableCell(2, 0);
assertEquals("书籍版次", cell.getText());
测试4:跟随超链接:
网页中有很多的超链接,我们可以使用HttpUnit来模拟超链接的点击,例如网页中如果有个超链接如下:
<a href="httpUnitABC.jsp">HttpUnit ABC</a>
则可以使用下面的程序来吵到链接,然后模拟一个click动作来跟随这个超链接:
WebConversation webConversation = new WebConversation();
WebResponse response = webConversation.getResponse("http://localhost:8080/httpUnit/");
WebLink link = response.getLinkWith("HttpUnit ABC");
WebRequest clickRequest = link.getRequest();
WebResponse linkPage =webConversation.getResponse(clickRequest);
测试5:测试Cookie:
如果被测试的网页需要Cookie信息,您可以使用WebConversation的addCookie()方法发送Cookie信息
给网页,例如:
WebConversation webConversation = new WebConversation();
webConversation.addCookie("user", "taobaoge");
WebResponse response = webConversation.getResponse("http://localhost:8080/httpUnit/");
如果网页中包含了Cookie,您可以使用getCookieValue()方法取得网页中包含的Cookie信息,若网页包括下面的Scriptlet:
<%
Cookie cookie = new Cookie("customerId", "12345");
response.addCookie(cookie);
%>
可使用下面的方式來测试传回的Cookie信息:
assertEquals("taobaoge",webConversation.getCookieValue("user"));
测试6:Authorization:
如果您的网页中有预设的HTTP基本验证,则可以使用WebConversation的setAuthorization ()方法來设定验证信息,例如:
webConversation.setAuthorization("justin", "123456");
测试7:设定代理:
有的時候,您测试的目的网页可能必须通过代理服务器才能连上,你可以通过设定系统属性来设定HttpUnit使用代理,例如:
System.getProperties().put("proxySet", "true");
System.getProperties().put("proxyHost", "proxy.ntu.edu.tw");
System.getProperties().put("proxyPort", "8080");
如此之來,HttpUnit就會通过指定的代理服务器來发送请求与接受相应。
1.EasyMock总览:
接下来,让我告诉大家如何使用JUnit和EasyMock框架来进行单元测试。
我们的第一个例子非常简单,但是在现实情况下,你通常是在一些类里使用另外的一些类。在进行真正的测试之前,你可能需要做很多的工作,比喻说安置大量的环境代码,启动一种大型的、复杂的系统,可能是数据库、功过刘或者是某一种类型的IDE环境,你的预设环境代码需要是系统进入某种特定的状态,以便按照测试所需要的方法进行响应。但是这种工作不大可能很快就能完成。
为了对一部分类进行单元测试,你需要建立和控制另外一些类。最好的办法就是为需要测试的类创建一个模拟对象。你可以自己手工的编写类,也可以使用EasyMock来产生这些对象。
模拟对象提供了一种经过证明是成功的解决方案。当我们很难或不可能为某种难以处理的资源创建需要的状态或者存取某种资源受限时,你就可以使用模拟对象。
模拟对象取代真实对象的位置,用于测试一些与真实对象进行交互或依赖于真实对象的功能。模拟对象背后的基本思想就是创建轻量级的、可控制的对象来代替为了编写测试为需要使用的对象。模拟对象还能够让你指定和测试你的代码与模拟对象本身之间的交互。
说的再直白一点,一个模拟对象就是一个简单的接口或者是类,在里面你可以定义一个特定的方法调用之后的简单的输出。
2.被测试的方法:
public class IncomeCalc {
private ICalcMethod method;
private Position position;
public void setMethod(ICalcMethod method) {
this.method = method;
}
public void setPosition(Position position) {
this.position = position;
}
public double calc(){
return method.calc(position);
}
}
接口:
public interface ICalcMethod {
public abstract double calc(Position position);
}
枚举类:
public enum Position {
BOSS,PROGRAMMER,MANAGER
}
3.使用JUnit和EasyMock进行测试:
import static org.junit.Assert.*;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class IncomeCalcTest {
private ICalcMethod mock;
private IncomeCalc incomeCalc;
@Before
public void setUp() throws Exception {
//一、建立模拟对象
mock=EasyMock.createMock(ICalcMethod.class);
incomeCalc=new IncomeCalc();
}
/**
* expect方法告知EasyMock希望得到一个特定的方法,使用一些特定的参数,
* addReturn为某一个方法定义返回值。times方法定义了模拟对象将被调用几次。
* reply方法需要在让模拟对象可用之前被调用。
* 执行完测试之后,你可以调用verify方法来检查模拟对象是不是跟预期的一样被调用了。
*/
@Test
public void testCalc() {
//二、准备工作:记录:记录测试中所用到得方法、返回值和执行次数。
EasyMock.expect(mock.calc(Position.BOSS)).andReturn(7000.00).times(2);
EasyMock.expect(mock.calc(Position.MANAGER)).andReturn(5000.00);
//三、准备完后:设置mock对象为“回放”模式
EasyMock.replay(mock);
//四、进行测试
incomeCalc.setMethod(mock);
incomeCalc.setPosition(Position.BOSS);
assertEquals(7000.00, incomeCalc.calc());//因为预定测试2遍
assertEquals(7000.00, incomeCalc.calc());//否则会出错
incomeCalc.setPosition(Position.MANAGER);
assertEquals(5000.00, incomeCalc.calc());
//incomeCalc.setPosition(Position.PROGRAMMER);
//五、判断这个模拟对象中的所有的方法是否已经都执行了。
// 不是必需的步骤
EasyMock.verify(mock);
}
}
1.Failure
Failure指的是由于预期的结果与实际运行的测试的结果不同而导致的,例如当使用assertEquals()或其它assertXXX()方法断言失败时,就会报出Failure,如果发现Faulure,你就要去检查你的测试方法或者是被测试方法中编写的逻辑是否有误。
2.Error
Error指的是编写程序时没有考虑到的问题。在执行测试的断言之前,程序就因为某种类型的意外而停止,比喻说我们在操作数组的时候,因为存取超出索引会引发ArrayIndexOutOfBoundsException,这个时候程序就会报出Error,程序将无法运行下去,提前结束,这个时候你要检查被测试方法中是不是有欠缺考虑到地方。
3.测试代码:
package com.junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestErrorFailure {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void errorTest(){
int [] arr={1,2,3};
System.out.println("出现error:"+arr[4]);
}
@Test
public void failureTest(){
int [] arr={1,2,3};
assertEquals(3, arr[0]);
}
}
哪个先执行到,就先报哪个错误:
package com.junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestErrorFailure {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
//@Test
public void errorTest(){
int [] arr={1,2,3};
System.out.println("出现error:"+arr[4]);
}
@Test
public void failureTest(){
int [] arr={1,2,3};
System.out.println("出现error:"+arr[4]);
assertEquals(3, arr[0]);
}
}
4.Java中的Exception和Error:
Exception可以被人为的控制和处理,而Error不应该被认为的处理(如内存溢出,线程死锁)。
1.异常测试:
异常测试是 JUnit 4 中的最大改进。旧式的异常测试是在抛出异常的代码中放入 try 块,然后在 try 块的末尾加入一个 fail() 语句。例如,该方法测试被零除抛出一个 ArithmeticException:
public void testDivisionByZero() {
try {
int n = 2 / 0;
fail("Divided by zero!");
}
catch (ArithmeticException success) {
assertNotNull(success.getMessage());
}
}
该方法不仅难看,而且试图挑战代码覆盖工具,因为不管测试是通过还是失败,总有一些代码不被执行。在 JUnit 4 中,您现在可以编写抛出异常的代码,并使用注释来声明该异常是预期的:
@Test(expected=ArithmeticException.class)
public void divideByZero() {
int n = 2 / 0;
}
如果该异常没有抛出(或者抛出了一个不同的异常),那么测试就将失败。但是如果您想要测试异常的详细消息或其他属性,则仍然需要使用旧式的 try-catch 样式。
2. 可以忽略到测试:
也许您有一个测试运行的时间非常地长。不是说这个测试应该运行得更快,而是说它所做的工作从根本上比较复杂或缓慢。需要访问远程网络服务器的测试通常都属于这一类。如果您不在做可能会中断该类测试的事情,那么您可能想要跳过运行时间长的测试方法,以缩短编译-测试-调试周期。或者也许是一个因为超出您的控制范围的原因而失败的测试。例如,W3C XInclude 测试套件测试 Java 还不支持的一些 Unicode 编码的自动识别。不必老是被迫盯住那些红色波浪线,这类测试可以被注释为 @Ignore,如下所示:
// Java doesn't yet support
// the UTF-32BE and UTF32LE encodings
@Ignore public void testUTF32BE()
throws ParsingException, IOException, XIncludeException {
File input = new File("data/xinclude/input/UTF32BE.xml");
Document doc = builder.build(input);
Document result = XIncluder.resolve(doc);
Document expectedResult = builder.build(new File(outputDir, "UTF32BE.xml"));
assertEquals(expectedResult, result);
}
测试运行程序将不运行这些测试,但是它会指出这些测试被跳过了。
但是一定要小心。最初编写这些测试可能有一定的原因。如果永远忽略这些测试,那么它们期望测试的代码可能会中断,并且这样的中断可能不能被检测到。忽略测试只是一个权宜之计,不是任何问题的真正解决方案。
1.注解方法:
| Annotation | 含义 |
| @Test public void method() | 定义一个要测试的方法 |
| @Before public void method() | 在每一个测试之前都会被执行的方法,这个方法常常用来进行一 些测试环境的准备,比喻说读入输入数据,初始化类 |
| @After public void method() | 与@Before进行对应,做一个清理工作 |
| @BeforeClass public void method() | 在所有的测试开始之前执行,这个方法在类运行的时候运行, 而且只会运行一次,所以常常用来做一些所有的方法都要依赖 到工作,比喻说,数据库的链接。 |
| @AfterClass public void method() | 与@BeforeClass进行对应,做一些类级别的清理工作 |
| @Ignore | 表明方法是被忽略的,这个方法非常实用,比喻你的方法已经 修改,但是对应的测试方法还没有得到一致的修改的时候,可以 忽略掉这个测试方法先。 |
| @Test(expected=IllegalArgumentException.class) | 检查测试方法是不是抛出了对应的异常 |
| @Test(timeout=100) | 如果方法的执行操作所耗费的毫秒数>100MS,那么方法失败。 |
2.断言方法:

3.Before和After的简单测试:
package com.junit.demo;
public class MathDemo {
public int add(int a,int b){
return a+b;
}
public int div(int a,int b){
return a/b;
}
}JUnit测试:
package com.junit.test;
import static org.junit.Assert.*;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.junit.demo.MathDemo;
public class MathDemoTest {
private MathDemo demo;
private Logger logger=Logger.getLogger(this.getClass().getName());
@Before
public void setUp() throws Exception {
logger.info("测试开始的准备");
demo=new MathDemo();
}
@After
public void tearDown() throws Exception {
logger.info("测试结束前的操作");
demo=null;
}
@Test
public void testAdd() {
int actual=demo.add(4, 5);
int expected=9;
assertEquals(expected, actual);
}
@Test
public void testDiv() {
int actual=demo.div(9, 3);
int expected=3;
assertEquals(expected, actual);
}
}
输出结果:
2009-7-27 10:47:55 com.junit.test.MathDemoTest setUp
信息: 测试开始的准备
2009-7-27 10:47:55 com.junit.test.MathDemoTest tearDown
信息: 测试结束前的操作
2009-7-27 10:47:55 com.junit.test.MathDemoTest setUp
信息: 测试开始的准备
2009-7-27 10:47:55 com.junit.test.MathDemoTest tearDown
信息: 测试结束前的操作
|
@Before public void method() |
在每一个测试之前都会被执行的方法,这个方法常常用来进行一
些测试环境的准备,比喻说读入输入数据,初始化类 |
|
@After public void method() |
与@Before进行对应,做一个清理工作 |
2009年7月26日
1.自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) //指定可以用在什么地方,默认所有地方
@Retention(RetentionPolicy.RUNTIME ) //指定周期--运行时
public @interface HelloWorld {
//定义成员
public String name() default "hello";
}
2.编写解析方法
import java.lang.reflect.Method;
public class AnnotationParser {
public void parse(Object obj,String methodName){
Method[] ms=obj.getClass().getMethods();
for(Method m:ms){
if(m.getName().equals(methodName)){
if(m.isAnnotationPresent(HelloWorld.class)){
HelloWorld hWorld=m.getAnnotation(HelloWorld.class);
//System.out.println(hWorld.name());
try{
System.out.println("before...");
m.invoke(obj, null);
System.out.println("after...");
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
3.Junit测试
被测试的bean:
public class TestBean {
private String name;
public TestBean(String name) {
this.name = name;
}
@HelloWorld(name="change")
public String getName() {
System.out.println("getName executed...");
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return this.name;
}
}测试方法:
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import com.persia.annotation.AnnotationParser;
import com.persia.annotation.TestBean;
public class AnnotationTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void hello(){
TestBean tBean=new TestBean("testbean");
//System.out.println(tBean);
AnnotationParser aParser=new AnnotationParser();
aParser.parse(tBean, "getName");
}
}
1.配置主键类
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
/**
* 1.提供无参数构造器
* 2.实现序列号接口
* 3.重写hashCode和equals方法
* @author Administrator
*
*/
@Embeddable //用在实体里面,告诉JPA只是使用该类里面的属性作为持久化字段
public class AirLinePK implements Serializable{
private String startCityString;//北京PEK
private String endCityString;
public AirLinePK(){}
public AirLinePK(String endCityString, String startCityString) {
this.endCityString = endCityString;
this.startCityString = startCityString;
}
@Column(length=3)
public String getStartCityString() {
return startCityString;
}
public void setStartCityString(String startCityString) {
this.startCityString = startCityString;
}
@Column(length=3)
public String getEndCityString() {
return endCityString;
}
public void setEndCityString(String endCityString) {
this.endCityString = endCityString;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((endCityString == null) ? 0 : endCityString.hashCode());
result = prime * result
+ ((startCityString == null) ? 0 : startCityString.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AirLinePK other = (AirLinePK) obj;
if (endCityString == null) {
if (other.endCityString != null)
return false;
} else if (!endCityString.equals(other.endCityString))
return false;
if (startCityString == null) {
if (other.startCityString != null)
return false;
} else if (!startCityString.equals(other.startCityString))
return false;
return true;
}
}
2.配置实体bean
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
@Entity
public class AirLine {
private AirLinePK id;
private String name;
public AirLine() {
// TODO Auto-generated constructor stub
}
public AirLine(String endCityString, String startCityString, String name) {
this.id=new AirLinePK(startCityString,endCityString);
this.name = name;
}
@EmbeddedId //为实体的id
public AirLinePK getId() {
return id;
}
public void setId(AirLinePK id) {
this.id = id;
}
@Column(length=20)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3.Junit测试
package junit.test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.BeforeClass;
import org.junit.Test;
import com.persia.bean.AirLine;
import com.persia.bean.AirLinePK;
import com.sun.org.apache.bcel.internal.generic.NEW;
public class CompositePKTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
//@Test
public void save(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPACompositePKPU");
EntityManager entityManager=factory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(new AirLine("PEK","SHA","北京飞往上海"));
entityManager.getTransaction().commit();
entityManager.close();
factory.close();
}
//@Test
public void getAirLine(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPACompositePKPU");
EntityManager entityManager=factory.createEntityManager();
//entityManager.getTransaction().begin();
AirLine aLine=entityManager.find(AirLine.class, new AirLinePK("SHA","PEK"));
System.out.println("查询出来的航线:"+aLine.getName());
//entityManager.getTransaction().commit();
entityManager.close();
factory.close();
}
//@Test
public void updateAirLine(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPACompositePKPU");
EntityManager entityManager=factory.createEntityManager();
entityManager.getTransaction().begin();
AirLine aLine=entityManager.find(AirLine.class, new AirLinePK("SHA","PEK"));
aLine.setName("bj-sh");
aLine.setId(new AirLinePK("sh","bj"));//主键无法修改
entityManager.merge(aLine);
entityManager.getTransaction().commit();
entityManager.close();
factory.close();
}
@Test
public void deleteAirLine(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPACompositePKPU");
EntityManager entityManager=factory.createEntityManager();
entityManager.getTransaction().begin();
AirLine aLine=entityManager.find(AirLine.class, new AirLinePK("SHA","PEK"));
entityManager.remove(aLine);
entityManager.getTransaction().commit();
entityManager.close();
factory.close();
}
}
1.配置persistence.xml和log4j
配置persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="JPAManyToManyPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name = "hibernate.connection.driver_class" value = "com.mysql.jdbc.Driver"/>
<property name = "hibernate.connection.url" value = "jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=UTF-8"/>
<property name = "hibernate.connection.username" value = "root"/>
<property name="hibernate.max_fetch_depth" value="3"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
配置log4j.properties
# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
log4j.rootLogger=INFO, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=/hello.log
log4j.appender.logfile.MaxFileSize=512KB
# Keep three backup files.
log4j.appender.logfile.MaxBackupIndex=3
# Pattern to output: date priority [category] - message
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
2.配置实体bean
student:
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
@Entity
public class Student {
private Integer id;
private String name;
private Set<Teacher> teachers=new HashSet<Teacher>();
public Student(){}
public Student(String name){
this.name=name;
}
@Id @GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(length=10,nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//一般在多对多很少用到级联的操作。
/**
* inverseJoinColumns关系被维护端的外键在中间表中的定义
* JoinColumns 关系维护端的外键在中间表中的定义
*/
@ManyToMany(cascade=CascadeType.REFRESH)
@JoinTable(name="student_teacher"
,inverseJoinColumns=@JoinColumn(name="teacherid")
,joinColumns=@JoinColumn(name="studentid"))
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
//关系的维护
public void addTeachers(Teacher teacher){
this.teachers.add(teacher);
}
public void removeTeachers(Teacher teacher){
if(this.teachers.contains(teacher))//通过Teacher重载的hashCode方法来判断
this.teachers.remove(teacher);
}
}teacher:
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import com.sun.org.apache.bcel.internal.generic.NEW;
@Entity
public class Teacher {
private Integer id;
private String name;
private Set<Student> student=new HashSet<Student>();
public Teacher(){}
public Teacher(String name) {
super();
this.name = name;
}
@Id @GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(length=10,nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(mappedBy="teachers",cascade=CascadeType.REFRESH
,fetch=FetchType.LAZY)//关系被维护端
public Set<Student> getStudent() {
return student;
}
public void setStudent(Set<Student> student) {
this.student = student;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Teacher other = (Teacher) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
3.Junit测试
package junit.test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.BeforeClass;
import org.junit.Test;
import com.persia.bean.Student;
import com.persia.bean.Teacher;
import com.sun.org.apache.bcel.internal.generic.NEW;
public class ManyToManyTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
//@Test
public void save(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPAManyToManyPU");
EntityManager eManager=factory.createEntityManager();
eManager.getTransaction().begin();
eManager.persist(new Student("学生1"));
eManager.persist(new Teacher("老师1"));
eManager.getTransaction().commit();
eManager.close();
factory.close();
}
/**
* 建立老师与学生的关系
*/
//@Test
public void buildRelation(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPAManyToManyPU");
EntityManager eManager=factory.createEntityManager();
eManager.getTransaction().begin();
Student student=eManager.find(Student.class, 2);
student.addTeachers(eManager.getReference(Teacher.class, 2));
//eManager.merge(arg0)直接更新即可:在托管中,且em是打开的。
eManager.getTransaction().commit();
eManager.close();
factory.close();
}
/**
* 解除关系
*/
//@Test
public void relieveRelation(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPAManyToManyPU");
EntityManager eManager=factory.createEntityManager();
eManager.getTransaction().begin();
Student student=eManager.find(Student.class, 1);
student.removeTeachers(eManager.getReference(Teacher.class, 1));
//当前处于托管状态,而且em是打开着的,所以直接删除即可。
eManager.getTransaction().commit();
eManager.close();
factory.close();
}
/**
* 删除老师
*/
//@Test
public void deleteTeacher(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPAManyToManyPU");
EntityManager eManager=factory.createEntityManager();
eManager.getTransaction().begin();
Student student=eManager.find(Student.class, 1);
Teacher teacher=eManager.getReference(Teacher.class, 1);
student.removeTeachers(teacher);
//先解除关系,再删除
eManager.remove(eManager.find(Teacher.class, 1));
//关系被维护端没有权力更新外键,此时此操作无法执行,有外键约束。
eManager.getTransaction().commit();
eManager.close();
factory.close();
}
/**
* 删除关系维护端
*/
//@Test
public void deleteStudent(){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("JPAManyToManyPU");
EntityManager eManager=factory.createEntityManager();
eManager.getTransaction().begin();
eManager.remove(eManager.find(Student.class, 2));
//关系维护端有权力更新外键。
eManager.getTransaction().commit();
eManager.close();
factory.close();
}
}
2009年7月25日
http://yangyiqian.javaeye.com/blog/365900
摘要:一般默认情况下,Eclipse ,MyEclipse 的代码提示功能是比Microsoft Visual Studio的差很多的,主要是Eclipse,MyEclipse本身有很多选项是默认关闭的,要开发者自己去手动配置。如果开发者不清楚的话,就不知道Eclipse ,MyEclipse的代码提示功能一样能像Microsoft Visual Studio的代码提示功能一样强大。
先举个简单的例子说明问题所在,例如在Eclipse ,MyEclipse代码里面,打个foreach,switch等这些,是无法得到代码提示的(不信自己试试),其他的就更不用说了,而在 Microsoft Visual Studio 里面是得到非常友好的代码提示的。实际上,Eclipse ,MyEclipse代码里面的代码提示功能默认的一般是点“.”,一般是有了点“.”,才会有代码提示。
原理:“Auto Activation triggers for java”这个选项就是指触发代码提示的的选项,把“.”改成“.abcdefghijklmnopqrstuvwxyz(,”的意思,就是指遇到26个字母和.,(这些符号就触发代码提示功能了。(具体后面有说,放心)
增强Eclipse ,MyEclipse 的代码提示功能,具体怎么样来配置?下面开始说步骤: 已在6.0 和6.5测试通过
1. 打开MyEclipse 6.0.1,然后“window”→“Preferences”
2. 选择“java”,展开,“Editor”,选择“Content Assist”。
3. 选择“Content Assist”,然后看到右边,右边的“Auto-Activation”下面的“Auto Activation triggers for java”这个选项。其实就是指触发代码提示的就是“.”这个符号。
“Auto activation delay”这个是延时,可以根据自己的需要进行设置。我设置的是10
4.“Auto Activation triggers for java”这个选项,在“.”后加abc字母,方便后面的查找
修改。然后“apply”,点击“OK”。
5. 然后,“File”→“Export”,在弹出的窗口中选择“Perferences”,点击“下一步”。
6. 选择导出文件路径,本人导出到桌面,输入“test”作为文件名,点击“保存”。
7. 在桌面找到刚在保存的文件“test.epf”,右键选择“用记事本打开”。
8. 可以看到很多配置MyEclipse 6.0.1的信息
9. 按“ctrl + F”快捷键,输入“.abc”,点击“查找下一个”。
10. 查找到“.abc”的配置信息如下:
如下:
/instance/org.eclipse.jdt.ui/content_assist_autoactivation_triggers_java=.abc
11. 把“.abc”改成“.abcdefghijklmnopqrstuvwxyz”,保存,关闭“test.epf”。
12. 回到MyEclipse 6.0.1界面,“File”→“Import”,在弹出的窗口中选择“Perferences”,点击“下一步”,选择刚在已经修改的“test.epf”文件,点击“打开”,点击“Finish”。该步骤和上面的导出步骤类似。
13. 最后当然是进行代码测试了。随便新建一个工程,新建一个类。在代码输入switch,foreach等进行测试。你立即会发现,果然出了提示,而且无论是敲哪个字母都会有很多相关的提示了,很流畅,很方便。
总结:
“Auto Activation triggers for java”这个选项就是指触发代码提示的的选项,把“.”改成“.abcdefghijklmnopqrstuvwxyz(,”的意思,就是指遇到26个字母和.,(这些符号就触发代码提示功能了。
顺便说一下,修改类名,接口名等以不同颜色高亮的,可以这样配置在“java”→“enditor”→ “syntac”,右边展开“java”→“classes”,勾上“Enable”这个选项,选择自己喜欢的颜色即可。当然还有其他相关的颜色配置。具体就不说啦。其实,在“Preferences”这个东西,有很多可以配置的东西,使得MyEclipse 优化的,具体的就要各个人根据自己个人喜好去配置了。谢谢。
----
经过测试,在MyEclipse 7.1下该设置也正常
http://minfirefox.javaeye.com/blog/269046
修改mysql的引擎为INNODB,可以使用外键,事务等功能,性能高。
修改my.ini,在[mysqld]下加上
default-storage-engine=INNODB
保存,重启。