Tìm

contraivietnam.tk

Một đời người, một rừng cây

Chuyên mục

Uncategorized

Những sinh viên mỗi bữa chỉ ăn một gói mỳ tôm

Cô giáo viên tương lai Lưu Thị H. V, sinh viên năm cuối khoa Ngữ Văn trường ĐH Sư Phạm Hà Nội là ví dụ cay đắng về thế hệ sinh viên thế kỉ 21 với mỗi bữa ăn một gói mì.

Bài toán chi tiêu bên hầu bao eo hẹp

Là con gái lớn trong một gia đình không khá giả ở miền quê hoa phượng đỏ, cô đã phải gánh trên vai gánh nặng gấp đôi gấp ba bạn bè cùng trang lứa. Đi dạy thêm một tháng 3 triệu đồng, nhưng cô vẫn ăn mì tôm cả tháng trời.

Lí giải điều lạ lùng đó, cô chia sẻ: “Mình có một đứa em đang học ĐH Hàng hải và một người mẹ nhiều bệnh tật. Tiền đi làm trong một tháng, mình phải gửi về cho mẹ mua thuốc, cho em đi học, và tiền nhà mỗi tháng của mình nữa. Nếu không ăn mì, mình không biết phải làm sao để chăm lo cho những người thân trong gia đình”.

Nếu không ăn mì, mình không biết phải làm sao để chăm lo cho những người thân trong gia đình”

Và thế là ngày nào cũng vậy, cô gái chịu thương chịu khó ấy đi dạy thêm 2 – 3 ca, thường là đi từ sáng sớm, đến giảng đường buổi chiều, và tan học lại tất tả đi dạy. Một gói mì 4 nghìn đồng cho một bữa ăn và một cuộc sống không lúc nào ngơi nghỉ.

My – SV năm thứ tư trường ĐH Kinh Tế mỗi ngày chỉ tiêu 10 nghìn đồng cho bữa sáng và bữa trưa. Mẹ cô bị mù hai mắt, bố bỏ đi biệt tích, em gái đang học trung cấp, miệng ăn của ba người trông chờ vào số tiền ít ỏi My đi làm thuê hàng ngày như đóng gạch hoặc may nón. Buổi sáng cô lót dạ bằng một cái bánh mỳ 2000 đồng, còn buổi trưa thì đi xin nước sôi trong bệnh viện Bạch Mai để ăn mỳ tôm. My tâm sự: “Ngày ba gói mì, trưa hai gói, ăn xong đi học, tối về ăn tiếp một gói. Liên tục như vậy đến gần hết một học kì thì người bắt đầu yếu đi trông thấy. Cho đến một hôm toàn thân bỗng nổi mẩn đỏ như bị phát ban, chân tay rã rời không nhấc lên nổi.

Bạn bè cùng phòng lo lắng đánh gió, đánh cảm cho mình đủ cách mà không đỡ. Cuối cùng mình mình phải về quê đi khám. Kết quả, cơ thể suy nhược nghiêm trọng, lượng hồng cầu trong máu bị suy giảm, gan bị nhiễm độc. Sau lần ấy, dạ dày của mình cũng bị ảnh hưởng…”

“Ăn cho người, mặc cho người”

Người xưa có câu: “Ăn cho mình, mặc cho người”, nhưng với những bạn nữ “hơi mập” hiện tại, câu nói đó chỉ đúng một nửa. Nếu phải sở hữu một thân hình tròn mẩy, “eo bánh mì” thì đó thực sự là điều kinh hoàng với các nữ sinh. Thay vì rèn luyện thể dục thể thao, các bạn ấy chọn cách ăn mì tôm giảm cân, vừa nhàn thân mà lại có vẻ hiệu quả(?!).

Hải Vân, cử nhân năm cuối lớp Ngữ văn, Đại học Sư Phạm Hà Nội lý giải cho việc trưa ăn mì, tối ăn mì như thế này: “Vòng hai của mình càng ngày càng tệ! Quần áo bó sát của mình bây giờ đều trong trạng thái không thể sử dụng. Ăn mì tôm là lựa chọn tốt nhất của mình trong thời gian này, hi vọng có thể cải thiện tình hình và lấy lại vóc dáng”.

Nguyễn Mai, sinh viên năm ba khoa Kế toán,  Đại học Bách khoa, vừa đi học vừa đi dạy thêm, ngày nào cũng về nhà lúc 21h – 22h trong trạng thái mệt mỏi. Nhưng tối nào cô cũng làm bạn với bát mì, cô chia sẻ : “Ăn đêm thường rất nhanh mập, nên mình chỉ dám ăn mì tôm, thi thoảng làm cái bánh mì đổi vị, ngoài ra không dám ăn thêm gì khác”.

Sở thích có một không hai

Bạn bè của Ngọc Linh, sinh viên năm nhất Học viện Báo chí – Tuyên truyền vẫn còn truyền tai nhau câu chuyện cô nàng thích ăn mì tôm, mà lại là mì tôm sống. Người ta thường bảo nhau, nhai mì tôm sống không khác gì bò nhai bã mía, nhưng với cô bạn cá tính này, được ăn mì tôm sống là cả một sở thích để đời.

Sáng nào cũng vậy, thay vì ăn một chút đồ ăn nóng hổi hay uống chút sữa, ly café, cô bạn này chỉ chăm chăm ào tới thùng mì tôm dự trữ và ngồi nhai mì tôm rau ráu. Một tháng thì 30 sáng cô nhai mì tôm, không hề chán nản.  Cô chia sẻ: “ Ăn nhiều rồi quen, mình không thể không có mì tôm buổi sáng được. Nếu không ăn, mình cảm thấy rất khó chịu”. Và thế là cho đến tận bây giờ, cái điệp khúc buổi sáng – mì tôm, buổi sáng – mì tôm luôn gắn bó thân thiết với cô bạn.

Nhóm nam sinh viên lớp Xây dựng dân dụng và công nghiệp của Quang Tuấn – Đại học Xây Dựng còn có sở thích ăn mì tôm rất độc đáo mà mỗi lần nghĩ đến, mọi người không khỏi phì cười. Lúc đêm khuya, nhóm nam sinh này thường rủ nhau dùng sục điện cắm thẳng vào một xô nước to đùng ngay giữa nhà. Khi nước sôi, có bao nhiêu mì tôm là các chàng trai thả hết vào xô nước đã đun, rồi lại mỗi người một bát, một đũa, thi nhau ăn uống và sung sướng với cảnh đời sinh viên cùnclip_image001g ăn, cùng ngủ, cùng học và hát bài ca “ Đã là bạn suốt đời là bạn”.

Quang Tuất chia sẻ: “Con trai tụi mình thường không mấy quan trọng chuyện ăn uống, nhưng hễ mấy anh em trong phòng mà thấy đói bụng là rủ nhau chơi trò ăn mì tập thể. Có khi, tụi mình bày trò thi nhau ăn mì, ai phạt sẽ phải mua mì về cho cả phòng ăn lần sau. Ăn mì trở thành truyền thống của phòng mình”.

Tiến sĩ Phan Thị Sửu (Giám đốc Trung tâm kỹ thuật an toàn vệ sinh thực phẩm, thuộc Hội Khoa học Kỹ thuật an toàn thực phẩm Việt Nam) cho biết thành phần của mì ăn liền chứa nhiều chất béo bão hòa, chất bột và ít chất xơ.

Ngoài ra, trong gói gia vị của mì chứa nhiều chất phụ gia có tác dụng làm ngon miệng. Song, những chất này cũng không có dinh dưỡng và còn cay nóng, gây bất lợi cho người cao huyết áp hoặc có thân nhiệt cao

Về mặt dinh dưỡng, mì ăn liền chủ yếu cung cấp bột và đạm thực vật. Do đó, mì ăn liền thiếu cân bằng dinh dưỡng bởi thiếu đạm động vật và vitamin từ rau quả tươi. Bởi vậy, không nên dùng mì ăn liền thay cho các bữa ăn chính hằng ngày vì nó chỉ cung cấp nhiều calo chứ không cung cấp đủ vitamin hay protein cho cơ thể.

Lao động

 

Theo Chiêm Khổng (VNN)

 

Sự tích Tình yêu

Ngày xửa ngày xưa, có một hòn đảo nơi đó có tất cả mọi cảm xúc sinh sống: Hạnh Phúc, Nỗi Buồn, Tri Thức và những cái khác, bao gồm cả Tình Yêu. Một ngày kia, các cảm xúc được thông báo rằng hòn đảo này sẽ chìm, vì vậy tất cả đều đóng thuyền và rời đi, ngoại trừ Tình Yêu.
Tình Yêu là người duy nhất ở lại. Tình Yêu muốn chống chọi đến giờ phút cuối cùng khi hòn đảo sắp chìm, Tình Yêu mới quyết định nhờ giúp đỡ.
Sự Giầu Có đang đi qua Tình Yêu trên một chiếc thuyền rất lớn. Tình Yêu nói: “Giàu Có ơi, có thể đưa tôi đi cùng với không?” Sự Giàu Có trả lời: “Không, tôi không thể. Trong thuyền có rất nhiều vàng và bạc, ở đây không có chỗ cho anh đâu.”
Tình Yêu bèn quyết định nhờ Phù Hoa, người cũng đi qua trên một con thuyền rất đẹp: “Phù Hoa, hãy giúp tôi!”. “Tôi không thể giúp anh, Tình Yêu ạ. Anh quá ẩm và có thể sẽ làm ẩm thuyền của tôi,” Phù Hoa trả lời.
Nỗi Buồn đang ở gần đó, Tình Yêu hỏi: ” Nỗi Buồn ơi, hãy cho mình đi với cậu”, “Ôi, Tình Yêu, mình buồn quá, mình chỉ muốn được ở một mình …”
Bỗng nhiên có một tiếng gọi: “Lại đây Tình Yêu. Ta sẽ đưa cháu đi”, đó là một người lớn tuổi. Quá vui mừng và sung sướng. Tình Yêu quên cả hỏi họ đang đi đâu. Khi đến một miền đất khô ráo, người lớn tuổi đó lại tiếp tục đi con đường của mình.
Tình Yêu hỏi Tri Thức, một người đứng tuổi khác:
– Ai đã vừa giúp cháu vậy ?
– Đó là Thời Gian – Tri Thức trả lời
– Thời Gian ư ? – Tình Yêu hỏi – Nhưng tại sao Thời Gian lại giúp cháu?
Tri Thức mỉm cười khôn ngoan và nói: “Bởi lẽ chỉ có Thời Gian mới hiểu được giá trị của Tình Yêu”

“Chỉ có thời gian mới hiểu được giá trị của tình yêu”. Niềm vui và nỗi buồn, khổ đau và hạnh phúc, tất cả những điều khiến ta mỉm cười hay rơi lệ cũng đều sẽ trôi qua. Sự giàu sang, tiền tài danh vọng chẳng phải rồi sẽ không còn là điều quan trọng? Khi nhìn lại con đường ta đã đi qua, chỉ xin được hy vọng rằng, hãy còn có Tình Yêu.
Rất có thể một lúc nào đó ta hờn trách Tình Yêu sao sớm lấy đi của ta sự vô tư, không phải lúc nào Tình Yêu cũng là chốn thiên đường, thế nhưng trên tất cả được chờ đợi và được sống trong Tình Yêu bao giờ cũng là niềm may mắn của mỗi con người.

Hãy đợi, chỉ có thời gian mới hiểu được tình yêu.

Ngày xửa ngày xưa, có một hòn đảo nơi đó có tất cả mọi cảm xúc sinh sống: Hạnh Phúc, Nỗi Buồn, Tri Thức và những cái khác, bao gồm cả Tình Yêu. Một ngày kia, các cảm xúc được thông báo rằng hòn đảo này sẽ chìm, vì vậy tất cả đều đóng thuyền và rời đi, ngoại trừ Tình Yêu.
Tình Yêu là người duy nhất ở lại. Tình Yêu muốn chống chọi đến giờ phút cuối cùng khi hòn đảo sắp chìm, Tình Yêu mới quyết định nhờ giúp đỡ.
Sự Giầu Có đang đi qua Tình Yêu trên một chiếc thuyền rất lớn. Tình Yêu nói: “Giàu Có ơi, có thể đưa tôi đi cùng với không?” Sự Giàu Có trả lời: “Không, tôi không thể. Trong thuyền có rất nhiều vàng và bạc, ở đây không có chỗ cho anh đâu.”
Tình Yêu bèn quyết định nhờ Phù Hoa, người cũng đi qua trên một con thuyền rất đẹp: “Phù Hoa, hãy giúp tôi!”. “Tôi không thể giúp anh, Tình Yêu ạ. Anh quá ẩm và có thể sẽ làm ẩm thuyền của tôi,” Phù Hoa trả lời.
Nỗi Buồn đang ở gần đó, Tình Yêu hỏi: ” Nỗi Buồn ơi, hãy cho mình đi với cậu”, “Ôi, Tình Yêu, mình buồn quá, mình chỉ muốn được ở một mình …”
Bỗng nhiên có một tiếng gọi: “Lại đây Tình Yêu. Ta sẽ đưa cháu đi”, đó là một người lớn tuổi. Quá vui mừng và sung sướng. Tình Yêu quên cả hỏi họ đang đi đâu. Khi đến một miền đất khô ráo, người lớn tuổi đó lại tiếp tục đi con đường của mình.
Tình Yêu hỏi Tri Thức, một người đứng tuổi khác:
– Ai đã vừa giúp cháu vậy ?
– Đó là Thời Gian – Tri Thức trả lời
– Thời Gian ư ? – Tình Yêu hỏi – Nhưng tại sao Thời Gian lại giúp cháu?
Tri Thức mỉm cười khôn ngoan và nói: “Bởi lẽ chỉ có Thời Gian mới hiểu được giá trị của Tình Yêu”

“Chỉ có thời gian mới hiểu được giá trị của tình yêu”. Niềm vui và nỗi buồn, khổ đau và hạnh phúc, tất cả những điều khiến ta mỉm cười hay rơi lệ cũng đều sẽ trôi qua. Sự giàu sang, tiền tài danh vọng chẳng phải rồi sẽ không còn là điều quan trọng? Khi nhìn lại con đường ta đã đi qua, chỉ xin được hy vọng rằng, hãy còn có Tình Yêu.
Rất có thể một lúc nào đó ta hờn trách Tình Yêu sao sớm lấy đi của ta sự vô tư, không phải lúc nào Tình Yêu cũng là chốn thiên đường, thế nhưng trên tất cả được chờ đợi và được sống trong Tình Yêu bao giờ cũng là niềm may mắn của mỗi con người.

Hãy đợi, chỉ có thời gian mới hiểu được tình yêu.

I. Bai tap Testing Junit…..

Đề Tài:
Những người thực hiện:
+ Trần Đình Lương. MSSV
+ Nguyễn Ngọc Tuyền.
+ Hồ Thanh Bình.
—————******—————-

I. Giới thiệu JUnit
JUnit là một framework đơn giản dùng cho việc tạo các unit testing tự động, và chạy các test có thể lặp đi lặp lại. Nó chỉ là một phần của họ kiến trúc xUnit cho việc tạo các unit testing. JUnit là một chuẩn trên thực tế cho unit testing trong Java. JUnit về nguồn gốc được viết bởi 2 tác giả Erich Gamma và Kent Beck 1
Giới thiệu:

JUnit có những đặc điểm đáng lưu tâm như sau:
• Xác nhận (assert) việc kiểm tra kết quả được mong đợi
• Các Test Suite cho phép chúng ta dễ dàng tổ chức và chạy các test
• Hỗ trợ giao diện đồ họa và giao diện dòng lệnh
Các test case của JUnit là các lớp của Java, các lớp này bao gồm một hay nhiều các phương thức unit testing, và những test này lại được nhóm thành các Test Suite.
Mỗi phương thức test trong JUnit phải được thực thi nhanh chóng. Tốc độ là điều tối quan trọng vì càng nhiều test được viết và tích hợp vào bên trong quá trình xây dựng phần mềm, cần phải tốn nhiều thời gian hơn cho việc chạy toàn bộ Test Suite. Các lập trình viên không muốn bị ngắt quãng trong một khoãng thời gian dài trong khi các test chạy, vì thế các test mà chạy càng lâu thì sẽ có nhiều khả năng là các lập trình viên sẽ bỏ qua bước cũng không kém phần quan trọng này.
Các test trong JUnit có thể là các test được chấp nhận hay thất bại, các test này được thiết kế để khi chạy mà không cần có sự can thiệp của con người. Từ những thiết kế như thế, bạn có thể thêm các bộ test vào quá trình tích hợp và xây dựng phần mềm một cách liên tục và để cho các test chạy một cách tự động
1. Đặt vấn đề
Mọi chương trình đều phải
đi kèm với bộ số liệu kiểm thử. Tuy nhiên, hoạt động này chưa thực sự phổ biến trong
chương trình giảng dạy lập trình và công nghệ phần mềm tại một số trường đại học ở
nước ta. Người lập trình thường xem nhẹ việc kiểm thử, đơn giản vì đó là một công
việc nhàm chán, ít gây hứng thú. Nhưng kiểm thử là một hoạt động quan trọng và
không thể thiếu được nhằm phát hiện lỗi trong chương trình, từ đó nâng cao năng suất
và đảm bảo chất lượng sản phẩm phần mềm. Beck và Gamma là những người đầu tiên
phát triển công cụ mã nguồn mở JUnit để hỗ trợ việc kiểm thử. Bài viết này sẽ trình
bày lại một ví dụ minh họa việc áp dụng JUnit bằng việc đưa ra một thiết kế đơn giản
và hợp lý để giải quyết bài toán đặt ra.

2. Lợi ích của JUnit
JUnit tránh cho người lập trình phải làm đi làm lại những việc kiểm thử nhàm chán
bằng cách tách biệt mã kiểm thử ra khỏi mã chương trình, đồng thời tự động hóa việc
tổ chức và thi hành các bộ số liệu kiểm thử.

Thoạt tiên, khi sử dụng JUnit, ta có thể có cảm giác là JUnit chỉ làm mất thêm thời
gian cho việc kiểm thử: Thay vì phải viết thêm các lớp và phương thức mới phục vụ
cho công tác kiểm thử, ta có thể soạn nhanh một bộ số liệu rồi viết ngay vào trong
phương thức main() và quan sát ngay kết quả kiểm thử. Vì quá trình soạn số liệu và
quá trình kiểm thử diễn ra đồng thời, nên ta sẽ dễ dàng nhận biết được ngay chương
trình đã chạy đúng trên bộ số liệu kiểm thử hay không, mà không cần nhìn vào tín
hiệu “xanh” mà JUnit có thể hỗ trợ.

3. Ví dụ minh họa
Sau đây là một ví dụ minh họa với những yêu cầu mới dần dần được thêm vào: Hãy
thiết kế lớp tiền tệ. Tiền tệ được đặc trưng bằng số tiền và đơn vị tiền (chẳng hạn
VND hoặc USD). Trước yêu cầu này, ta dễ dàng viết ra lớp Money:

public class Money {
private double amount;
private String currency;

public Money(double amount, String currency) {
this.amount = amount;
this.currency = currency;
}
}

Bây giờ giả sử rằng ta chỉ cần xử lý một loại tiền tệ duy nhất, chẳng hạn tiền Việt
Nam. Hãy hiện thực phương thức dưới đây để cộng hai số tiền cùng loại với nhau, và
dùng JUnit để kiểm thử chương trình.
Money add(Money money)

Do đó sẽ phải hiệu chỉnh class Money để giải quyết vấn đề đặt ra:
public class Money {
// Phần tương tự như trong Hình 1 đã được lược bớt

public Money add(Money money) {
return new Money(this.amount + money.amount, this.currency);
}
}

import junit.framework.Assert;
import junit.framework.TestCase;

public class MoneyTest extends TestCase {
public void testAdd() {
Money m1 = new Money(200, “VND”);
Money m2 = new Money(1000, “VND”);
Money result = m1.add(m2); // đối tượng lưu kết quả tính toán
Money expected = new Money(1200, “VND”); // kết quả dự kiến
Assert.assertTrue(result.equals(expected)); // lệnh kiểm thử
}
}

Phần kiểm thử có bốn điểm đáng chú ý sau:
1. Phương thức kiểm thử cần được đặt tên bắt đầu bằng từ test
2. Đối tượng lưu kết quả tính toán,
3. Đối tượng lưu kết quả dự kiến, và
4. Kiểm chứng sự trùng khớp giữa kết quả tính toán và kết quả dự kiến.

Ở đây ta đã dùng lệnh assertTrue() và phương thức equals() vì kết quả và dự kiến là
hai đối tượng. Nếu kết quả và dự kiến thuộc kiểu dữ liệu nguyên thủy (primitive), chẳng hạn int,
thì ta có thể dùng một trong hai lệnh sau:
Assert.assertTrue(result == expected);
Assert.assertEquals(result, expected);

Lệnh kiểm chứng thứ hai sẽ cung cấp nhiều thông tin hơn nếu kết quả tính toán và dự
kiến không trùng khớp nhau, từ đó giúp người lập trình nhanh chóng phát hiện lý do
gây ra lỗi bên trong chương trình. (Thi hành việc kiểm thử JUnit trong môi trường
Eclipse: Chọn lớp kiểm thử → Kích vào menu Run → Run As → JUnit Test. Có thể
cần click vào thẻ JUnit ở phía dưới bên trái màn hình để thấy được tín hiệu “xanh”
hoặc “đỏ”)

Sau khi thi hành JUnit Test, ta sẽ gặp tín hiệu “đỏ” (Hình 3), nghĩa là chương trình đã
có lỗi. Để có được tín hiệu “xanh”, ta cần định nghĩa lại (override) phương thức
equals() bên trong lớp Money để so sánh bằng giữa hai đối tượng (đoạn code dưới).

public class Money {
// Phần tương tự như trong Hình 2 đã được lược bớt

public boolean equals(Object object) {
if (object instanceof Money) {
Money money = (Money)object;
return this.amount == money.amount &&
this.currency == money.currency;
}
return false;
}
}

Ta cũng cần viết mã để kiểm thử tính đúng đắn của phương thức equals() (Hình 5).
Sau khi thi hành JUnit Test, ta sẽ được tín hiệu “xanh” (Hình 6). Điều cần lưu ý là
phương thức equals() Ở đoạn code trên không thật sự an toàn nếu số tiền có phần thập phân,
nhưng chi tiết tế nhị này được cố ý bỏ qua để đơn giản hóa vấn đề đang đề cập.

Quan sát mã kiểm thử ở Hình 5, ta thấy cần phải tổ chức lại vì đã có sự trùng lặp mã.
Để loại bỏ sự trùng lặp mã này, ta có thể chuyển hai đối tượng cục bộ m1 và m2 thành
hai thuộc tính riêng tư. (Chuyển biến cục bộ thành thuộc tính lớp trong môi trường
Eclipse: Kích vào biến cục bộ cần chuyển → menu Refactor → Convert Local
Variable to Field… → Initialize in: Field declaration)

Bây giờ giả sử rằng ta lại có thêm một yêu cầu mới: Các đơn vị kinh doanh có thể giữ
nhiều hơn một loại tiền, chẳng hạn vừa có VND vừa có USD. Khi thêm một loại tiền
khác với loại tiền hiện có thì chương trình không được cộng vào số tiền hiện có mà
phải lưu trữ riêng loại tiền mới này. Ví dụ, nếu hiện thời ta có 1200 VND, thì sau khi
thêm 10 USD, ta sẽ có 1200 VND và 10 USD. Hãy thiết kế chương trình để thực hiện
yêu cầu trên.

Để hoàn thành yêu cầu, ta sẽ thiết kế thêm một lớp mới có tên là MoneyBag để lưu trữ
một danh sách các loại tiền khác nhau, và viết thêm một lớp kiểm thử mới
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class MoneyBag {
private List monies = new ArrayList();

public String toString() {
String s = “{ “;
Iterator iter = monies.iterator();
while (iter.hasNext())
s += iter.next() + ” “;
return s + “}”;
}

public void add(Money money) {
for (int i = 0; i < monies.size(); i++) {
Money m = (Money)monies.get(i);
if (money.getCurrency().equals(m.getCurrency())) {
monies.set(i, m.add(money));
return;
}
}
// money is a new currency
monies.add(money);
}
}

import junit.framework.Assert;
import junit.framework.TestCase;

public class MoneyBagTest extends TestCase {
public void testAddWithToString() {
MoneyBag bag = new MoneyBag();
Assert.assertEquals(bag.toString(), "{ }");

bag.add(new Money(1200, "VND"));
Assert.assertEquals(bag.toString(), "{ [1200 VND] }");

bag.add(new Money(10, "USD"));
Assert.assertEquals(bag.toString(), "{ [1200 VND] [10 USD] }");
}
}

Khi thi hành JUnit Test, ta sẽ gặp tín hiệu “đỏ”. Bằng việc chèn lệnh
System.out.println() vào phương thức testAddWithToString(), ta sẽ phát hiện ra kết
quả phải là { [1200.0 VND] }, thay vì { [1200 VND] }. Từ đó ta biết rằng cần phải hiệu
chỉnh kết quả để được tín hiệu “xanh”. Điều này một lần nữa cho thấy điểm tế nhị khi
phải thực hiện việc so sánh trên các số thực.

Sau đây là câu hỏi dành cho bạn đọc trước khi tôi trình bày tiếp: Tại sao không
viết phương thức equals() trong lớp MoneyBag và sử dụng nó trong JUnit Test?

Ngoài việc dùng phương thức toString() để kiểm thử, ta còn có thể viết phương thức
equals() và một phương thức bổ trợ, được đặt tên là contains(), để kiểm tra xem đối
tượng MoneyBag có chứa một đối tượng Money cho trước không.

Vì MoneyBag chỉ chứa các đối tượng Money phân biệt, nên khi xét tính bằng nhau
giữa hai đối tượng MoneyBag trong phương thức equals(), ta chỉ cần kiểm chứng đối
tượng này có phải là tập con của đối tượng kia và số phần tử của hai đối tượng cần
bằng nhau là đủ. Việc kiểm thử tính đúng đắn của các phương thức equals() được thể
hiện trong phương thức testEquals(). Ngoài ra, vì thuộc tính của phương
thức bổ trợ contains() là private nên ta không thể kiểm thử riêng phương thức này
trong lớp MoneyBagTest, mà đã chuyển vào phương thức main() của lớp MoneyBag.

public class MoneyBag {
// Phần tương tự như trong Hình 7 đã được lược bớt

private boolean contains(Money money) {
Iterator iter = monies.iterator();
while (iter.hasNext()) {
if (money.equals((Money)iter.next()))
return true;
}
return false;
}

public boolean equals(Object object) {
if (object instanceof MoneyBag) {
MoneyBag bag = (MoneyBag)object;
if (monies.size() != bag.monies.size())
return false;
Iterator iter = bag.monies.iterator();
while (iter.hasNext()) {
Money m = (Money)iter.next();
if (!monies.contains(m))
return false;
}
return true;
}
return false;
}

public static void main(String[] args) {
MoneyBag bag = new MoneyBag();
Money m1 = new Money(1200, "VND"); Money m2 = new Money(10, "USD");

System.out.println(!bag.contains(m1));

bag.add(m1);
System.out.println(bag.contains(m1));
System.out.println(!bag.contains(m2));

bag.add(m2);
System.out.println(bag.contains(m2));
}
}

public class MoneyBagTest extends TestCase {
public void testAddWithToString() {
……………….
}

public void testAddWithEquals() {
MoneyBag bag1 = new MoneyBag();
MoneyBag bag2 = new MoneyBag();
Assert.assertTrue(bag1.equals(bag2));

bag1.add(new Money(1200, "VND"));
Assert.assertFalse(bag1.equals(bag2));

bag1.add(new Money(10, "USD"));

bag2.add(new Money(10, "USD"));
bag2.add(new Money(1200, "VND"));
Assert.assertTrue(bag1.equals(bag2));
}
}

Để kết hợp đồng thời nhiều lớp lớp kiểm thử khác nhau, ta có thể viết ra một bộ kiểm
thử (TestSuit). (Trong môi trường Eclipse: Kích vào
menu File → New → Other… → Java → JUnit → TestSuit → Next → Finish)

import junit.framework.Test;
import junit.framework.TestSuite;

public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite(“Test for Money”);
suite.addTest(new TestSuite(MoneyTest.class));
suite.addTest(new TestSuite(MoneyBagTest.class));
return suite;
}
}
II. Giới thiệu Unit Testing

– Xin mở đầu bằng một tình huống thế này: Anh Chuột được assign một task là viết một hàm kiểm tra tính hợp lệ cho dữ liệu nhập vào một text box. Dữ liệu này là một chuỗi các chữ số và dấu chấm của một số kiểu double có giá trị lớn hơn hoặc bằng 0. Giá trị chuỗi chỉ được chứa tối đa 1 chữ số sau dấu chấm. Chuỗi số này có thể là giá trị của số nguyên tức là không có dấu chấm nào cả, và cuối cùng giá trị của số nhập vào phải nằm trong khoảng 0 đến 100. Với nhiều điều kiện ràng buộc như vậy anh Chuối quyết định áp dụng Test Driven Development kết hợp với Unit Test để thực hiện và Anh Chuột đã viết một hàm test thể hiện mọi yêu cầu như sau:

Code 1: Ví dụ về một hàm test

– Tất nhiên sau khi viết hàm Test, Anh Chuột sẽ bắt tay vào implement class NumberChecker để cái test này pass. Anh Chuột cho rằng nên kết hợp Regular Expression và các hàm Parse của kiểu double là nhanh nhất , do đó Anh Chuột đã làm như sau:

Code 2: Implement lớp checknumber để Unit Test pass

– Lúc đó, trong team của Anh Chuột có chị Bưởi là một QC khét tiếng khó chịu, chị Bưởi này có tật là test và soi mói chương trình rất kĩ và đã phát hiện ra rất nhiều bug hiểm hóc mà một developer chân chính như Anh Chuột không ngờ tới. Sau khi test, chị Bưởi phát hiện ra rằng nếu người ta nhập vào 000 thì chương trinh vẫn cho nhập, ngược lại khi nhập +100 thì chương trình báo lỗi không hợp lệ. Phát hiện được bug này chị Bưởi rất vui và assign liền 1 bug cho anh Chuối với status là critical.

– Rõ ràng là Anh Chuột đã tính toán thiếu một số trường hợp. Hàm test sẽ được thêm vào một số dòng code để check các trường hợp chị Bưởi liệt kê, đồng thời regular expression của Anh Chuột phải được sửa lại cho đúng.

– Trong ngành phần mềm, thuật ngữ Unit Testing là một phương pháp dùng để kiểm tra tính đúng đắn của một đơn vị source code. Một Unit (đơn vị) source code là phần nhỏ nhất có thể test được của chương trình. Trong lập trình thủ tục, một unit có thể là cả chương trình, một function hay một procedure. Còn trong lập trình hướng đối tượng, đơn vị nhỏ nhất có lẽ là một method của một class nào đó.

– Điều kiện lý tưởng nhất là mỗt test case phải độc lập với những test case khác. Người ta có thể dùng nhiều kĩ thuật như stubs, mock hoặc fake objects, … để phục vụ việc test các module trong chương trình. Viết Unit test là trách nhiệm, nghĩa vụ và quyền lợi của các lập trình viên, lập trình viên chúng ta nên sử dụng Unit Test để bảo đảm những gì mình viết chạy đúng như yêu cầu phần mềm, và nhất là đúng với cách mình hiểu.
II.1 Lợi ích của Unit Test

– Nhiều . Mục đích của Unit Test là cô lập từng phần của chương trình và đảm bảo những phần đó chạy đúng như yêu cầu. Unit test giúp bảo đảm tính chính xác của chương trình, nó giúp thiết lập những ràng buộc và những phần code của chúng ta phải thực hiện chính xác những ràng buộc đó. Kết quả là Unit Test đem lại rất nhiều lợi ích, nhưng rõ ràng nhất là nó giúp phát hiện lỗi và những vấn đề liên quan ngay từ những phase đầu tiên của quá trình phát triển phần mềm.
II.2 Unit Test giúp cho việc sửa đổi dễ dàng hơn

– Trên lý thuyết, Unit Test cho phép lập trình viên refactor code và bảo đảm những gì anh ta viết vẫn chạy đúng sau khi code bị thay đổi. Để làm được điều này, người ta buộc phải viết các test case cho tất cả các function và methods và do đó bất cứ một thay đổi nào làm chương trình chạy sai sẽ bị phát hiện kịp thời và buộc người gây lỗi phải fix ngay. Còn trong thực tế để những test case của bạn cover hết toàn bộ những trường hợp trong chương trình lại là một vấn đề khác.

– Nếu như team của bạn có sử dụng những hệ thống build tự động như CruiseControl.NET có sử dụng Nunit test thì mỗi lần commit code gây lỗi sẽ dễ dàng phát hiện thủ phạm như hình dưới đây:

Hình 1: Giao diện Report của CruiseControl.NET

II.3 Unit test giúp tính hợp code dễ hơn

– Bạn làm việc trong một team, mỗi người làm một phần của chương trình và mỗi phần bạn viết đều đã apply unit test kĩ càng. Đến khi kết hợp những thành phần của team với nhau, quá trình đó nói chung sẽ rất xuông sẽ và ít lỗi hơn nhiều so với việc mạnh ai nấy code rồi cuối cùng merge lại với nhau.
II.4 Document và Design

– Mỗi một test case bạn viết có thể được xem như API document cho chính method được test. Một team member vào sau bạn có thể dự vào test case đó để hiểu hàm này công dụng là gì, input thế nào và output ra sao.

– Trong quá trình phát triển phần mềm, document của chương trình bao gồm các design, requirement có thể bị bỏ quên và trở nên “out of date” nhưng những Unit Test Cases sẽ luôn chính xác những gì chương trình thực hiện và vì vậy ở một khía cạnh nào đó, Unit Test có thể được xem như một dạng document của chương trình.
II.5 Những hạn chế của Unit Test

– Người ta khó có thể viết Unit Test để bắt tất cả các lỗi của 1 chương trình. Thêm vào đó, những test case ta viết chỉ kiểm lỗi những unit nhỏ nhất của chương trình do đó không thể nào lường trước những vấn đề có thể xảy ra khi kết hợp các module với nhau. Unit testing sẽ thể hiện được hiệu quả rõ nhất khi kết hợp nó với những kĩ thuật test khác và tất nhiên sẽ cần tới sức người. Unit Testing không thể nào thay thế được QC – Tester và cũng như nhiều kiểu test khác, nó chỉ có thể kiểm tra được những lỗi đã biết chứ không thể sử dụng nó để tìm ra các lỗi tiềm ẩn của chương trình.

– Software testing là một tổ hợp của nhiều trường hợp. Ví dụ như để kiểm tra một hàm trả về kiểu boolean, tức là có hai trường hợp trả về chúng ta thường phải viết ít nhất hai dòng code để test lần gọi hàm đó. Anh Nguyễn Văn Chuối rất thường viết những hàm dài cả trăm dòng code với nhiều if / else, làm sao bảo đảm rằng anh Chuối có thể viết một test case có thể cover hết những trường hợp có thể xảy ra. Trong trường hợp đó anh Chuối có thể refactor code để chia nhỏ thân hàm thành nhiều hàm nhỏ hơn rồi từ đó test các hàm nhỏ đó. Nếu team của bạn có sử dụng một Continuous Enviroment với NCoverExplorer thì sẽ dễ dàng phát hiện test case của bạn cover bao nhiêu % chương trình:

Hình 2: Giao diện Report của NCover trong dashboard của CruiseControl.NET

– Có nhiều trường hợp khác chúng ta không thể nào sử dụng Unit Test, chẳng hạn như không thế test private class, private method, … nên nói chung Unit Test là một công cụ hỗ trợ chứ không thể thay thế các kĩ thuật test đang được nhiều người sử dụng.
III. Một số tool và framework hỗ trợ Unit Testing

III.1 NUnit:
Là một unit-testing framework cho ngôn ngữ lập trình .NET được port từ Junit. NUnit có hai dạng là console và GUI. Thực sự thì NUnit thường được sử dụng kết hợp với CruiseControl.NET và dùng để test tự động trên build server, và lập trình viên bình thường cũng không cần download về máy làm gì.
III.2 TestDriven.NET:
Là một trong những tool không thể thiếu đối với dân .NET. Khi install vào máy, nó sẽ tích hợp một menu vào Visual Studio.NET và cho phép chúng test, debug các class/method rất tiện lợi, ngoài ra ta có thể sử dụng assembly nunit.framework trong thư mục cài đặt của TestDriven.NET để sử dụng cho project test.

Hình 3: Menu run test khi cài TestDriven.NET
III.3 NCover, NCoverExplorer:
Như giới thiệu ở trên, các tool này giúp chúng ta kiểm soát mức độ cover của các test case đối với source code, và cũng giống như NUnit, chúng thường được kết hợp với CruiseControl.NET để report sau khi source code được build tự động.
III.4 NMock, NMock2, Rhino Mock và TypeMock

– Các tool trên giúp chúng ta giả lập một object để test một component của chương trình khi mà component này có reference đến một component khác. Chúng ta sẽ sử dụng các kĩ thuật mock này để test project EnterpriseSample.Core bằng cách giả lập các object kiểu IxxxDao mà không cần đến EnterpriseSample.Data. Cách sử dụng các tool trên tương đối giống nhau và sẽ được ví dụ bằng Rhino Mock trong phần dưới đây, thông dụng nhất có lẽ là Rhino Mock và Type Mock
IV. Tạo project test sử dụng NUnit và Rhino Mock
Bài viết này được dịch,- Người ta thường tạo một project dạng class library dành cho các test class. Project này theo đúng tên gọi của nó chỉ có ý nghĩa để test và không có vai trò gì trong sản phầm phần mềm cuối cùng. Thực ra NUnit có thể test bất kí test class nào bên trong một assembly bất kì nên project test có thể là Console application, window application, v.v nhưng thông thường người ta sẽ chọn project loại class library. Có một lưu ý là test class của bạn phải được khai báo public, test method cũng thế. Khi sử dụng NUnit.Framework, các bạn sẽ phải làm quen với những Attribute như [TestFixture], [Test], [Setup], [TearDown], … xin được giải thích ngắn gọn những Attribute thường được sử dụng nhất như sau:
[TestFixture]: Dùng để đánh đấu 1 class là test class, những class khác không có Attribute này sẽ mặc định bị ignore khi NUnit test assembly của bạn.
[Test]: Dùng để đánh dấu 1 method là test method, ý nghĩa của nó tương tự như TestFixture nhưng scope ở cấp method.
[Setup]: Dùng để đánh dấu 1 method sẽ được gọi trước khi 1 test case được gọi. Nếu trong 1 test class có 10 method test, thì mỗi lần một method test được chạy thì NUnit sẽ chạy method được đánh dấu với Setup trước tiên.
[TearDown]: Ngược với Setup, chạy sau mỗi test method.
[TestFixtureSetup]: Tương tự như Setup nhưng ở cấp của class, khi 1 test class được test thì method nào được đánh dấu với attribute này sẽ được chạy trước tiên.
[TestFixtureTearDown]: Ngược với TestFixtureSetup.
– Vậy để apply NUnit Test thì công việc vô cùng đơn giản: tạo một project class library, thêm reference đến dll nunit.framework, thêm 1 class mới, khai báo nó thành public, thêm using nunit.framework, thêm attribute [TestFixture] vào đầu của class, viết một method test và khai báo với attribute [Test]. Cơ bản như vậy là đủ để test, bạn có thể kết hợp nhiều attribute khác cũng như nguyên tắc Inheritance của lập trình hướng đối tượng để có một project test uyển chuyển. Người ta thường sử dụng [Setup] để mở một transaction scope, sau đó dùng [TearDown] để roll back transaction khi test các Dao, như vậy sẽ không có dữ liệu bị thêm xóa vào database và bảo đảm dữ liệu test sẽ như nhau trước khi test các method. tóm tắt và bổ sung dựa vào bài viết NHibernate Best Practices with ASP.NET, 1.2nd Ed trên code Project. Các code sample trong bài dựa vào database Northwind của Microsoft và tham khảo 99,99% từ code mẫu của tác giả Billy McCafferty.

IV.1 Tạo dữ liệu test với NUnit

– Trên nguyên tắc, trước khi test bất kì một method test nào thì dữ liệu test phải như nhau. Ví dụ như bạn muốn test xem một Customer có thể thêm và xóa Order hay không thì trước khi test hàm AddOrder và DeleteOrder thông tin về Customer cũng như số lượng Order mà Customer đó đang giữ phải như nhau. Vì vậy người ta thường tạo những lớp Factory chỉ dành riêng để tạo ra dữ liệu Test nhất quán.

– Dữ liệu test của chúng ta trong trường hợp này là các object Customer, Order và HistoricalOrderSummary. Thế nên ta sẽ tạo ra các lớp Factory để tạo các List những object này, các lớp Factory này được đặt trong folder TestFactories bên trong project Test. Ví dụ nội dung lớp TestCustomerFactory như sau:

Code 3: Lớp Factory để tạo các object làm dữ liệu test
IV.2 Tạo các Mock Factory và Stub objects

– Nếu các bạn còn nhớ thì trong project EnterpriseSample.Core, ta đã khai báo các Interface DAO, các lớp Domain như Customer, Order sẽ reference đến những Interface này. Còn implementation thực sự của các interface Dao để truy xuất database được đặt ở project EnterpriseSample.Data. Như vậy khi test project EnterpriseSample.Core, người ta thường sử dụng các kĩ thuật Mock hoặc tạo một class implement các Interface này để test. Các Mock hay Stub này sẽ là cascadeur cho các lớp Dao khi ta test EnterpriseSample.Core. Đoạn code dưới đây sử dụng RhinoMock để tạo ra một mock object kiểu ICustomerDao, đóng thể cho CustomerDao:

Code 4: Sử dụng Rhino Mock để tạo một Mocked Dao object

– Anh Nguyễn Văn Chuối thuyết minh đoạn code trên như thế này: tui dùng MockRepository tạo ra một mock object thuộc kiểu ICustomerDao, đặt tên nó là mockedCustomerDao rồi nói với nó là: "lỡ ai có biểu mày lại hỏi mày có biết GetAll hay không thì mày trả lời là biết và đưa cho người ta danh sách Customer của thằng TestCustomersFactory. Còn ai hỏi mày biết GetById không thì cũng trả lời như vậy nghe chưa!". Cuối cùng tui dùng MockRepository để ghi nhớ thằng mock Object vừa được dặn dò kĩ lưỡng, bất cứ ai hỏi đển thằng mocked object này tui sẽ biểu nó ra nói chuyện.

– Thực ra trong bài viết này tác giả Billy McCafferty có thể sử dụng kĩ thuật Mock là đủ, nhưng theo tui nghĩ bác Billy McCafferty muốn cho chúng ta thấy có những cách khác mà không cần dùng Mock, vì thế nên có sự xuất hiện của lớp OrderDaoStub:

Code 5: Ví dụ một lớp Dao Stub dùng để test

– Khi implement 1 interface, buộc lòng chúng ta phải implement tất cả những gì được khai báo trong interface đó nên các bạn thấy rằng lớp Stub này phải khai báo rất nhiều hàm trong khi chúng ta chỉ muốn fake hàm GetByExample. Vì vậy dân đen như tụi mình cư dùng các kĩ thuật Mock cho lành.
IV.3 Test Các Domain classes

– Trên nguyên tắc, tất cả các dòng code của bạn viết phải được test qua có nghĩa là từng constructor, từng putblic setter, getter đều nên được test. Nhưng đối với những người có máu lười như tôi thì có thể bỏ qua một số thứ. Các lớp để test các domain class được đặt trong folder Domain bên trong project Test. Nếu bạn có 10 lớp Domain trong chương trình hãy viết 10 lớp test tương ứng ví dụ như sau:

Code 6: Viết Unit Test cho các Domain Classes
IV. 4 Test Nhibernate Dao
– Trong phần 3 này chúng ta hãy cứ tiếp tục chấp nhận điều sau: Khi một Dao cần truy xuất database, nó sẽ cần một Nhibernate Session để làm chuyện đó. Nó sẽ lấy Session này ở đâu? Nó sẽ lấy Session nhờ vào lớp NhibernateSessionManager và kết hợp với một giá trị string chứa đường dẫn của một file config chứa các setting cần thiết như Connection String đến database thực. Và đường dẫn này được hard code như là một static property của lớp TestGlobals.cs. Để tiếp tục, yêu cầu các bạn đang sử dụng db server SQL Express 2005 và đã có database Northwind. Nếu chưa có các bạn có thể download ở đây rồi attach Northwnd.MDF vào db server.

– Các lớp Nhibernate Dao là những lớp trực tiếp truy xuất database và chúng ta chuẩn bị test nó. Để test các lớp Dao này chúng ta cần một database thực sư và chúng ta đã chuẩn bị như đã nói ở trên. Xin nhắc lại một lần nữa là trên nguyên tắc, các hàm test nên không ảnh hưởng đến kết quả test của những hàm test khác, điều này có nghĩa là dữ liệu trước và sau khi thực hiện một hàm test là nhất quán. Để đạt được mục đích này, chúng ta tạo một lớp NhibernateTestCase, các lớp test case khác sẽ inherit từ lớp này. Trước khi tìm hiểu tại sao làm vậy, hãy xem implementation của nó:

Code 7: Lớp Test base

– Vậy bất kì lớp test nào inherit từ lớp này sẽ kế thừa được TestFixtureSetup và TestFixtureTearDown của nó. Có nghĩa là trước khi một lớp test được thực thi, NHIbernate Session Manager sẽ mở một transaction và rollback ngay sau khi test xong, nhờ thế dữ liệu test sẽ không bao giờ bị thay đổi. Còn bây giờ là nội dung một lớp Dao Test:

Code 8: Lớp Test NHibernate Dao

– Trong phần 2, chúng ta đã có một lớp Generic Dao giúp tiết kiệm code cho rất nhiều Dao Object khác nhau. Điều này dẫn đến việc là lớp Dao nào nên được test và lớp nào không? Để trả lời câu hỏi này, tác giả đã đưa ra các kinh nghiệm của mình khi viết Test Class:

+ Phải thực hiện test mọi method của Generic Dao. Nếu như bạn có 10 lớp Daos inherit generic Dao này thì chỉ một lớp bất kì trong số các lớp Daos này được test là đủ.
+ Phải test tất cả các method phụ của mỗi Dao nếu bạn có implement thêm.
+ Nếu có một lớp Dao nào không inherit từ Generic Dao như lớp HistoricalOrderSummaryDao thì lớp đó phải được test.
+ Phải chắc chắn dữ liệu test nhất quán trước và sau khi một Dao unit test được gọi và các unit test phải độc lập với nhau.
V. Tóm tắt & Kết luận

– Trong phần 3 này ta đã làm quen với Unit Testing, các tool và framework phụ trợ, ta cũng đã tìm hiểu qua công dụng và ý nghĩa của từng lớp, từng folder bên trong một project Test. Cách tổ chức lớp cũng như cách tác giả viết Unit Test rất tốt để tham khảo. Bản thân tôi cũng có viết Unit Test nhưng sau khi xem bài viết của Billy McCafferty thì đã quyết định từ nay về sau nếu có viết test sẽ theo cách làm của bác Billy.

– Viết Unit Test tuy không bắt buộc nhưng nó đóng vai trò quan trọng trong qúa trình làm phần mềm. Đối với một số khách hàng lớn họ có thể yêu cầu chúng ta viết Unit Test và phải thoả mãn cover 80% code chẳng hạn. Unit Test không hẳn chỉ để test chương trình, ta có thể sử dụng nó như là một công cụ hỗ trợ debug nhanh khi implement một chức năng nào đó khá phức tạp. Kết hợp với một số kĩ thuật Mock, ta có thể test ngay một module của chương trình khi chưa có hoặc chưa hoàn thành xong các module khác…

– Chắc hẳn chúng ta vẫn còn nhiều thắc mắc đối với cách hoạt động của lớp NhibernateSessionManager. Lớp này thực sự có công dụng gì và được tổ chức thế nào? Hãy chờ hồi sau sẽ rõ

Unit testing with JUnit and EasyMock

We all have it. It’s that piece of code in our project that everyone is afraid to change. It’s so confusing no one truly understands what is going on. We are all afraid that if we do change it, we’ll break it. You have just discovered my favorite reason for writing unit tests. But how do you write a unit test? What exactly is a unit test? How do I handle dependencies? And how is writing more code going to make my existing code better? This tutorial will show you how.
What is a unit test?
For the case of this tutorial, we’ll define a unit test as a test of a single isolated component in a repeatable way. Let’s go thru that one section at a time to get a clearer idea of what goes into a unit test.

“a test”. This means to verify something is correct. In order for us to have a valid unit test, we need to actually validate that after a start condition A, an end condition B exists. “…a single isolated component…”. This is what separates a unit test from other types of tests. In order for it to be a unit test, it must test something in isolation, aka without dependencies. The reason for this is that we are testing the component itself and not it’s interaction with other components (that is an integration test). Finally, although most definitions don’t include this piece, “…in a repeatable way” is a very important piece of the definition. It’s one thing to run a test that passes. It’s quite different to have something you can run in a repeatable manor at any point to see if changes you made effected how the component behaves. For example, if you choose to do some refactoring to improve performance, can you rerun your unit test to verify that you didn’t change the behavior of the component.

Setup
I will be using Eclipse 3.3 Europa to do this tutorial. To begin, create a new java project and call it JUnitTutorial. Right click on your new project and select New –> Folder. Name it lib and click Finish. Usually you don’t want to package your test code with your regular code, so let’s make an additional source directory, test. To do that, right click on your new project and select Properties. Select Java Build Path from the available options. In the Java Build Path window, click Add Folder. From the Add Folder dialog, select Create New Folder, name it test and click Finish. Next we need to add JUnit to our build path. Since it comes with Eclipse, all we need to do is to go to the Libraries tab, click the button Add Library, select JUnit and click Next. Select JUnit 4 and click Finish. Click ok to exit the Preferences window. We will also need to download and add the EasyMock jar files to our project. You can find the jars here. Once you download the zip file (we are using version 2.3 for this tutorial), extract the easymock.jar file and place it in the lib folder you created earlier. In Eclipse, right click on your project and select Properties. On the menu to the left, click Java Build Path and select the Libraries tab. Click the button Add Jar on the right. In the window that pops up, add the easymock.jar and click Ok. Click Ok to close the Properties window. You should now be ready to start your development.

The requirements
In test driven design, we develop the unit test before the functionality. We write a test that verifies that the class should do X after our call. We prove that the test fails, we then create the component to make the test pass. In this case, we are going to create a service with a method that authenticates a user. Below is a class diagram of the scenario.

The interfaces
We will start our coding by defining two interfaces, LoginService and UserDAO We will implement LoginService, however since in this tutorial UserDAO will be mocked, we won’t bother implementing it right now. For LoginService, we have a single method that takes a String userName and String password and returns a boolean (true if the user was found, false if it was not). The interface looks like this:

/**
* Provides authenticated related processing.
*/
public interface LoginService {

/**
* Handles a request to login. Passwords are stored as an MD5 Hash in
* this system. The login service creates a hash based on the paramters
* received and looks up the user. If a user with the same userName and
* password hash are found, true is returned, else false is returned.
*
* @parameter userName
* @parameter password
* @return boolean
*/
boolean login(String userName, String password);
}
The UserDAO interface will look very similar to the LoginService. It will have a single method that takes a userName and hash. The hash is an MD5 hashed version of the password, provided by the above service.

/**
* Provides database access for login related functions
*/
public interface UserDAO {

/**
* Loads a User object for the record that
* is returned with the same userName and password.
*
* @parameter userName
* @parameter password
* @return User
*/
User loadByUsernameAndPassword(String userName, String password);
}
The test case
Before we begin development, we will develop our test. Tests are structured by grouping methods that perform a test together in a test case. A test case is a class that extends junit.framework.TestCase. So in this case, we will begin by developing the test case for LoginService. To start, in your test directory, create a new class named LoginServiceTest and make it extend junit.framework.TestCase.

The lifecycle of a test execution consists of three main methods:

•public void setUp()
setUp is executed before each of the test. It is used to perform any setup required before the execution of your test. Your implementation will override the default empty implementation in TestCase.
•public void testSomething()
testSomething is the actual test method. You may have many of these within a single test case. Each one will be executed by your test runner and all errors will be reported at the end.
•public void tearDown()
tearDown is executed after each test method. It is used to perform any cleanup required after your tests.

So to begin flushing out our test case, we’ll start with the setUp method. In this method, we’ll instantiate an instance of the service to be tested. We’ll also create our first mock object, UserDAO. You can see the source of our test below.

import junit.framework.TestCase;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.easymock.EasyMock.eq;
/**
* Test case for LoginService.
*/
public class LoginServiceTest extends TestCase{

private LoginServiceImpl service;
private UserDAO mockDao;

/**
* setUp overrides the default, empty implementation provided by
* JUnit’s TestCase. We will use it to instantiate our required
* objects so that we get a clean copy for each test.
*/
@Override
public void setUp() {
service = new LoginServiceImpl();
mockDao = createStrictMock(UserDAO.class);
service.setUserDAO(mockDao);
}
}
EasyMock works by implementing the proxy pattern. When you create a mock object, it creates a proxy object that takes the place of the real object. The proxy object gets it’s definition from the interface you pass when creating the mock. We will define what methods are called and their returns from within our test method itself.

When creating a mock object, there are two types, a mock and a strict mock. In either case, our test will tell the mock object what method calls to expect and what to return when they occur. A basic mock will not care about the order of the execution of the methods. A strict mock, on the other hand, is order specific. Your test will fail if the methods are executed out of order on a strict mock. In this example, we will be using a strict mock.

The next step is to create our actual test method (for reference, we will not be implementing a tearDown method for this test case, it won’t be needed in this example). In our test method, we want to test the following scenario:

Even with the very basic method we want to test above, there are still a number of different scenarios that require tests. We will start with the “rosy” scenario, passing in two values and getting a user object back. Below is the source of what will be our new test method.


/**
* This method will test the “rosy” scenario of passing a valid
* username and password and retrieveing the user. Once the user
* is returned to the service, the service will return true to
* the caller.
*/
public void testRosyScenario() {
User results = new User();
String userName = “testUserName”;
String password = “testPassword”;
String passwordHash =
“�Ӷ&I7���Ni=.”;
expect(mockDao.loadByUsernameAndPassword(eq(userName), eq(passwordHash)))
.andReturn(results);

replay(mockDao);
assertTrue(service.login(userName, password));
verify(mockDao);
}

So let’s go thru the code above. First, we create the expected result of our DAO call, results. In this case, our method will just check to see if an object was returned, so we don’t need to populate our user object with anything, we just need an empty instance. Next we declare the values we will be passing into our service call. The password hash may catch you off guard. It’s considered unsafe to store passwords as plain text so our service will generate an MD5 hash of the password and that value is the value that we will pass to our DAO.

The next line is a very important line in our test that alot happens, so let’s walk thru it step by step:

1.expect(mockDao.loadByUsernameAndPassword()
This is a call to the static method EasyMock.expect. It tells your mock object to expect the method loadByUsernameAndPassword to be called.
2.eq(userName), eq(passwordHash)
This code isn’t always needed. When EasyMock compares the values passed to the method call, it does and == comparison. Because we are going to create the MD5 hash within our method, an == check will fail, so we have to use one of EasyMock’s comparators instead. The eq comparator in this case will compare the contents of the string using it’s .equals method. If we were not doing the MD5 hash, this line would be expect(mockDao.loadByUsernameAndPassword(userName, password).andReturn(results);
3..andReturn(results);
This tells our mock object what to return after this method is called.

The final three lines are the ones that do the testing work. replay(mockDao); tells EasyMock “We’re done declaring our expectations. It’s now time to run what we told you”. assertTrue(service.login(userName, password)); does two things: executes the code to be tested and tests that the result is true. If it is false, the test will fail. Finally, verify(mockDao); tells EasyMock to validate that all of the expected method calls were executed and in the correct order.

So that’s it for the test. Now all we have to do is write the code to make it pass. You can find that below.

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class LoginServiceImpl implements LoginService {

private UserDAO userDao;

public void setUserDAO(UserDAO userDao) {
this.userDao = userDao;
}

@Override
public boolean login(String userName, String password) {
boolean valid = false;
try {
String passwordHash = null;
MessageDigest md5 = MessageDigest.getInstance(“MD5”);
md5.update(password.getBytes());
passwordHash = new String(md5.digest());

User results =
userDao.loadByUsernameAndPassword(userName, passwordHash);
if(results != null) {
valid = true;
}
} catch (NoSuchAlgorithmException ignore) {}

return valid;
}
}
Conclusion
So that is it. I hope this gives you a more in depth view into JUnit and EasyMock. Unit testing is something that once you get used to it, makes you code better, provides you with a safety net for future refactoring and protects you from being burned by API changes. I strongly encourage that you give it a try. Until next time.

Attachments
Eclipse Project: JUnitClass.zip

26 Responses
•Jonny Andersson responded:
This was quite a good little tutorial as an introduction on how to use EasyMock! I still think it is hard to understand how to use EasyMock, and a continuation of this tutorial would have been great. The API documentation (javadoc) is not very superfluous so it is quite hard to understand the power of it without good examples like this tutorial. It takes a little time to learn how to “think” when creating mock objects, at least for me. I guess it at least would have been easier if they had created some more explanations in the class documentation (in top of the generated javadoc) for the EasyMock class, and for example a little code example on typical use, but there is no documentation at all. An alternative would havebeen to link to some online tutorial.

•sraju responded:
I am a research scholar working on software test case optimizations.

•Stephen Turner responded:
Several errors in the code….

– LoginService interface needs to define setUserDAO method
– @Override in LoginServiceImpl generates a compile error
– closing paren missing at the end of this line:
expect(mockDao.loadByUsernameAndPassword(eq(userName), eq(password))
– The way the testRosyScenario method is written, the passwordHash variable is not used (you hand “password” to loadByUsernameAndPassword). I actually had problems saving the source code with the hard-coded string (encoding issues).

It would be great if the tutorial went on to explain how to actually run the test and how to interpret the results.

•Michael responded:
Stephen,

Thanks for the feedback! A couple quick notes:
– LoginService is correct. The test calls LoginServiceImpl. The implementation has the getters and setters for dependencies, not the interface.
– @Override annotation works fine for me.
– I have fixed the typos on the expect line (the missing paren and the second eq() should take passwordHash and not password).
– I apologize for the encoding issue. MD5 hashes aren’t HTML friendly. My intent was that readers would get the drift.

I have also added a zip file of my Eclipse project that I used to develop this tutorial. I hope this will help mitigate any confusion on the code itself.

Regarding the execution of the test, you can execute it two ways in Eclipse:

– The first (and my favorite) is to use the keyboard shortcut. Press Alt+Shift+X then T (for test).
– The second is to right click on LoginServiceTest and select Run As –> JUnit Test.

Finally, in order to interpret the results, there will be a bar that turns red if there is a failure during the tests or green if they all pass. If it turns red, there will be a window below that will tell you what the error was and on what line. Would it be helpful to go over test debugging in a future tutorial?

Keep the good feedback coming!
Michael

•Medyk responded:
As Stephen wrote before LoginService interface needs to define setUserDAO method or ‘service’ field needs to be LoginServiceImpl in LoginServiceTest class.

•Haider Shah responded:
The tutorial is very nice, detailed and easy to learn. By reading it only once i got a clear understanding about the Mock.
But a question arise in my mind that don’t you think it is lengthy as it requires a lot of code just to test a single login module. so what we gona do with the large system having say having more than 20 modules or more…

Kindly mail me at the given address and clear my confusion.

Regards,
Haider Shah
shah.d.gr8@gmail.comThis e-mail address is being protected from spam bots, you need JavaScript enabled to view it
http://www.dolcha.com

•Haider Shah responded:
public class LoginServiceImpl implements LoginService {

private UserDAO userDao;

public void setUserDAO(UserDAO userDao) {
this.userDao = userDao;
}

‘setUserDAO’ should be defined in the LoginService interface but it is absent.

you over ride login method, you must also define setUserDao in the interface, it is lgical error.
@Override
public boolean login(String userName, String password) {
boolean valid = false;
try {

•Michael responded:
Thank you everyone for your feedback!

Regarding the setUserDAO() being missing from the LoginService interface, that really isn’t the issue. The test should be (and now does) refer to LoginServiceImpl instead of LoginService. LoginService should not have the setUserDAO() method on it because that dependency is an implementation detail and not something that the consumer of the API should care about (IMHO).

I have updated the tutorial to make the correct reference. Thanks again and keep the feedback coming!

Michael

•Stephen Turner responded:
Hi Michael,

Thanks for the feedback – my mistake on the setUserDAO mthod. I had changed the code from your example.

The @Override error I got was in the LoginServiceImpl class – this is the message: “The method login(String, String) of type LoginServiceImpl must override a superclass method”.

Thanks,
Steve

•Shridhar responded:
Hi Michael,
We are heavy users of Easymock for unit testing most of our application. But i feel its just a pain to setup all the mocks for complex classes which has lot of dependencies on other components. It becomes harder to maintain all the mock setup when you change something in the code base and then you end up spending half a day fixing it. Sometimes i feel its not worth it.

I find regression and integration tests very useful.

•Michael responded:
Shridhar,

I’m glad to hear that you are using EasyMock. From the description of your experience, I wonder if either your code is too complex or you are testing too much with each test. Keep in mind that unit testing is intended to test very small, isolated pieces. Excessive mocking is a tell tale sign of either your code (say a method in the unit testing scenario) is too complex and should be refactored into smaller pieces that can be unit tested separately or that you are testing too much and that the piece you are testing isn’t isolated enough. Good luck!

Michael

•Teja Kantamneni responded:
Its a pretty nice roundup on easymock, here is my little one on partial mocking of objects using easymock.
http://tejakantamneni.blogspot.com/2008/09/partial-mocking-of-objects-using.html

•Gayathri responded:
The tutorial is very simple and good, I started using easy mock for my DAO mock objects. And to start with this gives a easy understanding.

•Benjamin Lambe responded:
as for the @override this is a 1.5 JVM Specific annotation that tells the compiler that you are overriding this method with your own implementation.

In your code you are not actually overriding the login() method, but implementing it… so this @Override should be removed…. the reason why it will show up for some people and not others is if you have your compiler warnings/errors set up to show this.

Good tutorial though, I am a regular user of junit and easy mock, though i have to use easy mock 1.3 😥 becuase of our code base.

some of our tests can get extremely complex and you find yourself having to create lots of mocks, but helper methods help here where you create a helper method which will create the mock you are after and handles all the other mock creation for the objects you do not care about below it… so instead of creating 20 mock objects for your test you simply call

doCreateMockForxxx();

and you have helper methods for your expectations based on creating this mock

doSetUpExpectationsForxxx();

especially in testing workflow tests this is necessary, no matter how much you try and isolate your methods under test… one of my test files is 10,000 lines long 😉 but manageable…

I agree there are not enough tutorials on easymock etc… someone should really write some more (hint hint)

Keep up the good work

•Anjil responded:
Hi Michael,
The tutorial is interesting and useful. I was able to test some of my projects using EasyMock. But it needs me to always have the interface for every class which i want to mock. Is there any other way i can mock the classes without an inteface?

•Michael responded:
Anjil,

Thanks for the feedback. Regarding mocking classes, EasyMock has an additional package for that specific ability. Use org.easmock.classextension.EasyMock for mocking classes and org.easymock.EasyMock for mocking interfaces. I hope this helps. If not, let me know and I can go into more detail.

Michael

•Iftach responded:
Hi Michael,
I have one problem with the example. It’s still a bit coupled for me.

I think that the way LoginServiceImpl is handling the hash should also be injected into the LoginServiceImpl using a different service such as HashService.
That way you could test your HashService in another test case, and when testing the LoginServiceImpl, mock the HashService.

That kind of thinking gets me to respond on what Shridhar wrote.
I disagree with Michael that your code is too complex. It might be, but not necessarily. sometimes you have a lot of services in your program, and when writing a flow class that uses those services, you want to use more than one service, which is ok if non of the sub-flows has a meaning.
As you said it could make your test code a bit hard to manage.
I have 2 suggestions for you:
1. Test the edge cases using mocks (for an example: UserDao throws an exception). Usually test cases that test edge cases are clean.
2. Integration testing is a good idea in order to solve the problem, as long as you don’t do the integration tests all at once and just give up on unit tests.
Write different test cases that just integrate with 1-2 real services at a time. The rest of the services will still be mocked. It will keep your test code much cleaner. and will get some of the effect of unit testing.

Iftach

•hema responded:
His site gives the clear picture for junits using easyMock

•Andrew Cllegg responded:
Thanks for the nice demonstration!

BTW to those people having problems with @Override — it’s a JDK 1.5 vs. 6.0 thing. In 1.5 you can’t @Override an interface method, just a superclass method. In 6.0 you can, and to not do so causes a compiler warning. (Even though the terminology ‘override’ is wrong…)

•chary responded:
the greatest simplifier is the one who explains hard problem in a simplest possible way and not because to solve hard problem…this is one of the example

•Binu N Kavumkal responded:
Hi Michael,

The tutorial is very useful and it explains nicely the life cycle of a EazyMock and JUnit.

I have a couple of queries regarding mocking HttpServletRequest, HttpServletResponse and FilterChain

I want unit test a Filter class using EasyMock and JUnit.

In the doFilter(), I inspect the request parameter and if parameter contains a specific string, I would not allow the user to proceed further. Otherwise, user request can proceed.

How to test the Scenario?

In side the doFilter method based on the checking I am setting a flag.

I flag is true, I do the chain.doFilter(..)
Otherwise, sendRedirect to home page using response object.

If you have any idea, please let me know

•sakthi responded:
Hi … your Article is very nice, detailed and easy to get a clear view on Mock.
But it is lengthy as it requires a lot of code just to test a single login module. so what we gona do with the large system having many modules?…. I got another Article related to this from macrotesting site there its is very clear and they had used simple ideas in Mock that is good as your. you can see that article in http://www.macrotesting.com sure it will be useful. Thank you for this post…

•gunner007 responded:
hi, this is very useful. however i, still have questions and confusion about EasyMock and JUNit.

What is the relation of these two? I mean, JUnit can also be partnered with JMock.

Please advise. Thank you.

•akki responded:
How can we use easymock to test the EJB classes.
can any of you please provide an example as how to test some ejbs when we do RMI calls thru JUNIT test cases.

•chunjianyin responded:
it’s very good!

•Harihar responded:
This article was very helpful for me. It would be great if this tutorial is extended (like explaining more about the EasyMock and JUnit with some more examples).

Add your own comment…

Tìm hiểu JUnit Framework

JUnit là một framework đơn giản dùng cho việc tạo các unit testing tự động, và chạy các test có thể lặp đi lặp lại. Nó chỉ là một phần của họ kiến trúc xUnit cho việc tạo các unit testing. JUnit là một chuẩn trên thực tế cho unit testing trong Java. JUnit về nguồn gốc được viết bởi 2 tác giả Erich Gamma và Kent Beck

Giới thiệu
JUnit có thể được tải xuống từ địa chỉ http://www.junit.org.

JUnit có những đặc điểm đáng lưu tâm như sau:

• Xác nhận (assert) việc kiểm tra kết quả được mong đợi
• Các Test Suite cho phép chúng ta dễ dàng tổ chức và chạy các test
• Hỗ trợ giao diện đồ họa và giao diện dòng lệnh

Các test case của JUnit là các lớp của Java, các lớp này bao gồm một hay nhiều các phương thức unit testing, và những test này lại được nhóm thành các Test Suite.

Mỗi phương thức test trong JUnit phải được thực thi nhanh chóng. Tốc độ là điều tối quan trọng vì càng nhiều test được viết và tích hợp vào bên trong quá trình xây dựng phần mềm, cần phải tốn nhiều thời gian hơn cho việc chạy toàn bộ Test Suite. Các lập trình viên không muốn bị ngắt quãng trong một khoãng thời gian dài trong khi các test chạy, vì thế các test mà chạy càng lâu thì sẽ có nhiều khả năng là các lập trình viên sẽ bỏ qua bước cũng không kém phần quan trọng này.

Các test trong JUnit có thể là các test được chấp nhận hay thất bại, các test này được thiết kế để khi chạy mà không cần có sự can thiệp của con người. Từ những thiết kế như thế, bạn có thể thêm các bộ test vào quá trình tích hợp và xây dựng phần mềm một cách liên tục và để cho các test chạy một cách tự động

Ví dụ test các chức năng của một lớp
Bạn muốn viết các unit test với JUnit. Việc đầu tiên bạn phải tạo một lớp con thừa kế từ lớp junit.framework.TestCase. Mỗi unit test được đại diện bởi một phương thức testXXX() bên trong lớp con của lớp TestCase

Ta có một lớp Person như sau:

view plaincopy to clipboardprint?
1.public class Person {
2.private String firstName;
3.private String lastName;
4.public Person(String firstName, String lastName) {
5.if (firstName == null && lastName == null) {
6.throw new IllegalArgumentException(“Both names cannot be null”);
7.}
8.this.firstName = firstName;
9.this.lastName = lastName;
10.}
11.public String getFullName() {
12.String first = (this.firstName != null) ? this.firstName : “?”;
13.String last = (this.lastName != null) ? this.lastName : “?”;
14.return first + last;
15.}
16.public String getFirstName() {
17.return this.firstName;
18.}
19.public String getLastName() {
20.return this.lastName;
21.}
22.}
public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
if (firstName == null && lastName == null) {
throw new IllegalArgumentException(“Both names cannot be null”);
}
this.firstName = firstName;
this.lastName = lastName;
}
public String getFullName() {
String first = (this.firstName != null) ? this.firstName : “?”;
String last = (this.lastName != null) ? this.lastName : “?”;
return first + last;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
}

Sau đó ta sẽ viết một test case đơn giản để test một số phương thức của lớp trên

view plaincopy to clipboardprint?
1.import junit.framework.TestCase;
2.public class TestPerson extends TestCase {
3.public TestPerson(String name) {
4.super(name);
5.}
6./**
7.* Xac nhan rang name duoc the hien dung dinh dang
8.*/
9.public void testGetFullName() {
10.Person p = new Person(“Aidan”, “Burke”);
11.assertEquals(“Aidan Burke”, p.getFullName());
12.}
13./**
14.* Xac nhan rang nulls da duoc xu ly chinh xac
15.*/
16.public void testNullsInName() {
17.Person p = new Person(null, “Burke”);
18.assertEquals(“? Burke”, p.getFullName());
19.p = new Person(“Tanner”, null);
20.assertEquals(“Tanner ?”, p.getFullName());
21.}
22.}
import junit.framework.TestCase;
public class TestPerson extends TestCase {
public TestPerson(String name) {
super(name);
}
/**
* Xac nhan rang name duoc the hien dung dinh dang
*/
public void testGetFullName() {
Person p = new Person(“Aidan”, “Burke”);
assertEquals(“Aidan Burke”, p.getFullName());
}
/**
* Xac nhan rang nulls da duoc xu ly chinh xac
*/
public void testNullsInName() {
Person p = new Person(null, “Burke”);
assertEquals(“? Burke”, p.getFullName());
p = new Person(“Tanner”, null);
assertEquals(“Tanner ?”, p.getFullName());
}
}

Lưu ý: mỗi unit test là một phương thức public và không có tham số được bắt đầu bằng tiếp đầu ngữ test. Nếu bạn không tuân theo quy tắc đặt tên này thì JUnit sẽ không xác định được các phương thức test một các tự động.

Để biên dịch TestPerson, chúng ta phải khai báo gói thư viện junit trong biến đường môi trường classpath

set classpath=%classpath%;.;junit.jar
javac TestPerson

Để chạy một JUnit TestCase, ta có 2 cách

• Chạy với môi trường text, các bạn gõ lệnh

java junit.textui.TestRunner TestPerson

• Chạy với môi trường đồ họa

java junit.swingui.TestRunner TestPerson

Chúng ta có thể chạy trực tiếp các TestCase mà không muốn kích hoạt một trong các test runner của JUnit. Chúng ta sẽ thêm phương thức main() vào test case. Ví dụ:

view plaincopy to clipboardprint?
1.public class TestGame extends TestCase {
2.…
3.public static void main(String [args) {
4.junit.textui.TestRunner.run(new TestSuite(TestGame.class))
5.}
6.}
public class TestGame extends TestCase {

public static void main(String [args) {
junit.textui.TestRunner.run(new TestSuite(TestGame.class))
}
}

Các phương thức assertXXX()
Các phương thức assertXXX() được dùng để kiểm tra các điều kiện khác nhau. junit.framework.TestCase, lớp cha cho tất cả các test case, thừa kế từ lớp junit.framework.Assert. Lớp này định nghĩa khá nhiều các phương thức assertXXX(). Các phương thức test hoạt động bằng cách gọi những phương thức này.

Sau đây là mô tả các phương thức assertXXX() khác nhau có trong lớp junit.framework.Assert.

assertEquals(): So sánh 2 giá trị để kiểm tra bằng nhau. Test sẽ được chấp nhận nếu các giá trị bằng nhau

assertFalse(): Đánh giá biểu thức luận lý. Test sẽ được chấp nhận nếu biểu thức sai

assertNotNull(): So sánh tham chiếu của một đối tượng với null. Test sẽ được chấp nhận nếu tham chiếu đối tượng khác null

assertNotSame(): So sánh địa chỉ vùng nhớ của 2 tham chiếu đối tượng bằng cách sử dụng toán tử ==. Test sẽ được chấp nhận nếu cả 2 đều tham chiếu đến các đối tượng khác nhau

assertNull(): So sánh tham chiếu của một đối tượng với giá trị null. Test sẽ được chấp nhận nếu tham chiếu là null

assertSame(): So sánh địa chỉ vùng nhớ của 2 tham chiếu đối tượng bằng cách sử dụng toán tử ==. Test sẽ được chấp nhận nếu cả 2 đều tham chiếu đến cùng một đối tượng

assertTrue(): Đánh giá một biểu thức luận lý. Test sẽ được chấp nhận nếu biểu thức đúng

fail(): Phương thức này làm cho test hiện hành thất bại, phương thức này thường được sử dụng khi xử lý các biệt lệ

Mặc dù bạn có thể chỉ cần sử dụng phương thức assertTrue() cho gần như hầu hết các test, tuy nhiên thì việc sử dụng một trong các phương thức assertXXX() cụ thể sẽ làm cho các test của bạn dễ hiểu hơn và cung cấp các thông điệp thất bại rõ ràng hơn.

Tất cả các phương thức của bảng trên đều nhận vào một String không bắt buộc làm tham số đầu tiên. Khi được xác định, tham số này cung cấp một thông điệp mô tả test thất bại.

Ví dụ:

1.assertEquals(employeeA, employeeB);
2.assertEquals(“Employees should be equal after the clone() operation.”, employeeA, employeeB).
assertEquals(employeeA, employeeB);
assertEquals(“Employees should be equal after the clone() operation.”, employeeA, employeeB).

Phiên bản thứ 2 được ưa thích hơn vì nó mô tả tại sao test thất bại, điều này sẽ giúp cho việc sửa lỗi được dễ dàng hơn

Thế nào là một unit test tốt
Mỗi unit test chỉ nên kiểm tra phần cụ thể của một chức năng nào đó. Chúng ta không nên kết hợp nhiều test không liên quan với nhau lại vào trong một phương thức testXXX()

Ta có một lớp Game như sau

view plaincopy to clipboardprint?
1.public class Game {
2.private Map ships = new HashMap();
3.public Game() throws BadGameException {
4.}
5.public void shutdown() {
6.// dummy method
7.}
8.public synchronized Ship createFighter(String fighterId) {
9.Ship s = (Ship) this.ships.get(fighterId);
10.if (s == null) {
11.s = new Ship(fighterId);
12.this.ships.put(fighterId, s);
13.}
14.return s;
15.}
16.public boolean isPlaying() {
17.return false;
18.}
19.}
20.public class BadGameException extends Exception {
21.public BadGameException(String s) {
22.super(s);
23.}
24.}
public class Game {
private Map ships = new HashMap();
public Game() throws BadGameException {
}
public void shutdown() {
// dummy method
}
public synchronized Ship createFighter(String fighterId) {
Ship s = (Ship) this.ships.get(fighterId);
if (s == null) {
s = new Ship(fighterId);
this.ships.put(fighterId, s);
}
return s;
}
public boolean isPlaying() {
return false;
}
}
public class BadGameException extends Exception {
public BadGameException(String s) {
super(s);
}
}

Sau đó ta viết một đoạn test sau đây:

view plaincopy to clipboardprint?
1.public void testGame() throws BadGameException{
2.Game game = new Game();
3.Ship fighter = game.createFighter(“001”);
4.assertEquals(“Fighter did not have the correct identifier”, “001”, this.fighter.getId());
5.Ship fighter2 = this.game.createFighter(“001”);
6.assertSame(“createFighter with same id should return same object”, fighter, fighter2);
7.assertTrue(“A new game should not be started yet”, !this.game.isPlaying());
8.}
public void testGame() throws BadGameException{
Game game = new Game();
Ship fighter = game.createFighter(“001”);
assertEquals(“Fighter did not have the correct identifier”, “001”, this.fighter.getId());
Ship fighter2 = this.game.createFighter(“001”);
assertSame(“createFighter with same id should return same object”, fighter, fighter2);
assertTrue(“A new game should not be started yet”, !this.game.isPlaying());
}

Đây là một thiết kế không tốt vì mỗi phương thức assertXXX() đang kiểm tra phần không liên quan của chức năng. Nếu phương thức assertEquals() thất bại, phần còn lại của test sẽ không được thi hành. Khi xảy ra điều này thì chúng ta sẽ không biết các test khác có đúng chức năng hay không

Tiếp theo chúng ta sẽ sửa test trên lại để kiểm tra các khía cạnh khác nhau của trò chơi một cách độc lập.

view plaincopy to clipboardprint?
1.public void testCreateFighter() {
2.System.out.println(“Begin testCreateFigher()”);
3.assertEquals(“Fighter did not have the correct identifier”, “001”, this.fighter.getId());
4.System.out.println(“End testCreateFighter()”);
5.}
6.public void testSameFighters() {
7.System.out.println(“Begin testSameFighters()”);
8.Ship fighter2 = this.game.createFighter(“001”);
9.assertSame(“createFighter with same id should return same object”, this.fighter, fighter2);
10.System.out.println(“End testSameFighters()”);
11.}
12.public void testGameInitialState() {
13.System.out.println(“Begin testGameInitialState()”);
14.assertTrue(“A new game should not be started yet”, !this.game.isPlaying());
15.System.out.println(“End testGameInitialState()”);
16.}
public void testCreateFighter() {
System.out.println(“Begin testCreateFigher()”);
assertEquals(“Fighter did not have the correct identifier”, “001”, this.fighter.getId());
System.out.println(“End testCreateFighter()”);
}
public void testSameFighters() {
System.out.println(“Begin testSameFighters()”);
Ship fighter2 = this.game.createFighter(“001”);
assertSame(“createFighter with same id should return same object”, this.fighter, fighter2);
System.out.println(“End testSameFighters()”);
}
public void testGameInitialState() {
System.out.println(“Begin testGameInitialState()”);
assertTrue(“A new game should not be started yet”, !this.game.isPlaying());
System.out.println(“End testGameInitialState()”);
}

Với cách tiếp cận này, khi một test thất bại sẽ không làm cho các mệnh đề assertXXX() còn lại bị bỏ qua.
Có thể bạn sẽ đặt ra câu hỏi có khi nào một phương thức test chứa nhiều hơn một các phương thức assertXXX() hay không? Câu trả lời là có. Nếu bạn cần kiểm tra một dãy các điều kiện và các test theo sau sẽ luôn thất bại nếu có một test đầu tiên thất bại, khi đó bạn có thể kết hợp nhiều phương thức assert vào trong một test

Set Up và Tear Down
Hai phương thức setUp() và tearDown() là một phần của lớp junit.framework.TestCase Bằng cách sử dụng các phương thức setUp và tearDown. Khi sử dụng 2 phương thức setUp() và tearDown() sẽ giúp chúng ta tránh được việc trùng mã khi nhiều test cùng chia sẻ nhau ở phần khởi tạo và dọn dẹp các biến.

JUnit tuân thủ theo một dãy có thứ tự các sự kiện khi chạy các test. Đầu tiên, nó tạo ra một thể hiện mới của test case ứng với mỗi phương thức test. Từ đó, nếu bạn có 5 phương thức test thì JUnit sẽ tạo ra 5 thể hiện của test case. Vì lý do đó, các biến thể hiện không thể được sử dụng để chia sẻ trạng thái giữa các phương thức test. Sau khi tạo xong tất cả các đối tượng test case, JUnit tuân theo các bước sau cho mỗi phương thức test:

• Gọi phương thức setUp() của test case
• Gọi phương thức test
• Gọi phương thức tearDown() của test case

Quá trình này được lặp lại đối với mỗi phương thức test trong test case.

Sau đây chúng ta sẽ xem xét ví dụ

view plaincopy to clipboardprint?
1.public class Ship {
2.private String id;
3.public Ship(String id) {
4.this.id = id;
5.}
6.public String getId() {
7.return this.id;
8.}
9.}
10.public class TestGame extends TestCase {
11.private Game game;
12.private Ship fighter;
13.public void setUp() throws BadGameException {
14.this.game = new Game();
15.this.fighter = this.game.createFighter(“001”);
16.}
17.public void tearDown() {
18.this.game.shutdown();
19.}
20.public void testCreateFighter() {
21.System.out.println(“Begin testCreateFigher()”);
22.assertEquals(“Fighter did not have the correct identifier”,
23.”001″, this.fighter.getId());
24.System.out.println(“End testCreateFighter()”);
25.}
26.public void testSameFighters() {
27.System.out.println(“Begin testSameFighters()”);
28.Ship fighter2 = this.game.createFighter(“001”);
29.assertSame(“createFighter with same id should return same object”,
30.this.fighter, fighter2);
31.System.out.println(“End testSameFighters()”);
32.}
33.public void testGameInitialState() {
34.System.out.println(“Begin testGameInitialState()”);
35.assertTrue(“A new game should not be started yet”,
36.!this.game.isPlaying());
37.System.out.println(“End testGameInitialState()”);
38.}
39.}
public class Ship {
private String id;
public Ship(String id) {
this.id = id;
}
public String getId() {
return this.id;
}
}
public class TestGame extends TestCase {
private Game game;
private Ship fighter;
public void setUp() throws BadGameException {
this.game = new Game();
this.fighter = this.game.createFighter(“001”);
}
public void tearDown() {
this.game.shutdown();
}
public void testCreateFighter() {
System.out.println(“Begin testCreateFigher()”);
assertEquals(“Fighter did not have the correct identifier”,
“001”, this.fighter.getId());
System.out.println(“End testCreateFighter()”);
}
public void testSameFighters() {
System.out.println(“Begin testSameFighters()”);
Ship fighter2 = this.game.createFighter(“001”);
assertSame(“createFighter with same id should return same object”,
this.fighter, fighter2);
System.out.println(“End testSameFighters()”);
}
public void testGameInitialState() {
System.out.println(“Begin testGameInitialState()”);
assertTrue(“A new game should not be started yet”,
!this.game.isPlaying());
System.out.println(“End testGameInitialState()”);
}
}

Thông thường bạn có thể bỏ qua phương thức tearDown() vì mỗi unit test riêng không phải là những tiến trình chạy tốn nhiều thời gian, và các đối tượng được thu dọn khi JVM thoát. tearDown() có thể được sử dụng khi test của bạn thực hiện những thao tác như mở kết nối đến cơ sở dữ liệu hay sử dụng các loại tài nguyên khác của hệ thống và bạn cần phải dọn dẹp ngay lập tức. Nếu bạn chạy một bộ bao gồm một số lượng lớn các unit test, thì khi bạn trỏ tham chiếu của các đối tượng đến null bên trong thân phương thức tearDown() sẽ giúp cho bộ dọn rác lấy lại bộ nhớ khi các test khác chạy

Đôi khi bạn muốn chạy vài đoạn mã khởi tạo chỉ một lần, sau đó chạy các phương thức test, và bạn chỉ muốn chạy các đoạn mã dọn dẹp chỉ sau khi tất cả test kết thúc. Ở phần trên, JUnit gọi phương thức setUp() trước mỗi test và gọi tearDown() sau khi mỗi test kết thúc, vì thế để làm được điều như trên, chúng ta sẽ sử dụng lớp junit.extension.TestSetup để đạt được yêu cầu trên.

Ví dụ sau sẽ minh họa việc sử dụng lớp trên

view plaincopy to clipboardprint?
1.import junit.extensions.TestSetup;
2.import junit.framework.*;
3.public class TestPerson extends TestCase {
4.public TestPerson(String name) {
5.super(name);
6.}
7.public void testGetFullName() {
8.Person p = new Person(“Aidan”, “Burke”);
9.assertEquals(“Aidan Burke”, p.getFullName());
10.}
11.public void testNullsInName() {
12.Person p = new Person(null, “Burke”);
13.assertEquals(“? Burke”, p.getFullName());
14.p = new Person(“Tanner”, null);
15.assertEquals(“Tanner ?”, p.getFullName());
16.}
17.public static Test suite() {
18.TestSetup setup = new TestSetup(new TestSuite(TestPerson.class)) {
19.protected void setUp() throws Exception {
20.//Thực hiện các đoạn mã khởi tạo một lần ở đây
21.}
22.protected void tearDown() throws Exception {
23.//Thực hiện các đoạn mã dọn dẹp ở đây
24.}
25.};
26.return setup;
27.}
28.}
import junit.extensions.TestSetup;
import junit.framework.*;
public class TestPerson extends TestCase {
public TestPerson(String name) {
super(name);
}
public void testGetFullName() {
Person p = new Person(“Aidan”, “Burke”);
assertEquals(“Aidan Burke”, p.getFullName());
}
public void testNullsInName() {
Person p = new Person(null, “Burke”);
assertEquals(“? Burke”, p.getFullName());
p = new Person(“Tanner”, null);
assertEquals(“Tanner ?”, p.getFullName());
}
public static Test suite() {
TestSetup setup = new TestSetup(new TestSuite(TestPerson.class)) {
protected void setUp() throws Exception {
//Thực hiện các đoạn mã khởi tạo một lần ở đây
}
protected void tearDown() throws Exception {
//Thực hiện các đoạn mã dọn dẹp ở đây
}
};
return setup;
}
}

TestSetup là một lớp thừa kế từ lớp junit.extension.TestDecorator, Lớp TestDecorator là lớp cơ sở cho việc định nghĩa các test biến thể. Lý do chính để mở rộng TestDecorator là để có được khả năng thực thi đoạn mã trước và sau khi một test chạy. Các phương thức setUp() và tearDown() của lớp TestSetup được gọi trước và sau khi bất kỳ Test nào được truyền vào constructor,

Trong ví dụ trên chúng ta đã truyền một tham số có kiểu TestSuite vào constructor của lớp TestSetup

view plaincopy to clipboardprint?
1.TestSetup setup = new TestSetup(new TestSuite(TestPerson.class)) {
TestSetup setup = new TestSetup(new TestSuite(TestPerson.class)) {

Điều này có nghĩa là 2 phương thức setUp() được gọi chỉ một lần trước toàn bộ bộ test và tearDown() được gọi chỉ một lần sau khi các test trong bộ test kết thúc.

Chú ý: các phương thức setUp() và tearDown() bên trong lớp TestPerson vẫn được thực thi trước và sau mỗi phương thức test bên trong lớp TestPerson.

Tổ chức các test vào các test suite
Thông thường JUnit tự động tạo ra các Test Suite ứng với mỗi Test Case. Tuy nhiên bạn muốn tự tạo các Test Suite của riêng mình bằng cách tổ chức các Test vào Test Suite. JUnit cung cấp lớp junit.framework.TestSuite hỗ trợ việc tạo các Test Suite

Khi bạn sử dụng giao diện text hay graphic, JUnit sẽ tìm phương thức sau trong test case của bạn

view plaincopy to clipboardprint?
1.public static Test suite() { … }
public static Test suite() { … }

Nếu không thấy phương thức trên, JUnit sẽ sử dụng kỹ thuật reflection để tự động xác định tất cả các phương thức testXXX() trong test case của bạn, rồi thêm chúng vào một test suite. Sau đó nó sẽ chạy tất cả các test trong suite này. Bạn có thể tạo ra bản sao hành vi của phương thức suite() mặc định như sau

view plaincopy to clipboardprint?
1.public class TestGame extends TestCase{
2.…
3.public static Test suite() {
4.return new TestSuite(TestGame.class);
5.}
6.}
public class TestGame extends TestCase{

public static Test suite() {
return new TestSuite(TestGame.class);
}
}

Bằng cách truyền đối tượng TestGame.class vào construtor TestSuite, bạn đang thông báo cho JUnit biết để xác định tất cả các phương thức testXXX() trong lớp đó và thêm chúng vào suite. Đoạn mã trên không làm khác gì so với việc JUnit tự động làm, tuy nhiên bạn có thể thêm các test cá nhân để chỉ chạy các test nhất định nào đó hay là điều khiển thứ tự thực thi

view plaincopy to clipboardprint?
1.import junit.framework.*;
2.public class TestGame extends TestCase {
3.private Game game;
4.private Ship fighter;
5.public TestGame(String name) {
6.super(name);
7.}
8.…
9.public static Test suite() {
10.TestSuite suite = new TestSuite();
11.suite.addTest(new TestGame(“testCreateFighter”));
12.suite.addTest(new TestGame(“testSameFighters”));
13.return suite;
14.}
15.}
import junit.framework.*;
public class TestGame extends TestCase {
private Game game;
private Ship fighter;
public TestGame(String name) {
super(name);
}

public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new TestGame(“testCreateFighter”));
suite.addTest(new TestGame(“testSameFighters”));
return suite;
}
}

Bạn có thể kết hợp nhiều suite vào các suite khác. Bạn có ra ở đây đã sử dụng mẩu Composite. Ví dụ:

view plaincopy to clipboardprint?
1.public static Test suite() {
2.TestSuite suite = new TestSuite(TestGame.class);
3.suite.addTest(new TestSuite(TestPerson.class));
4.return suite;
5.}
public static Test suite() {
TestSuite suite = new TestSuite(TestGame.class);
suite.addTest(new TestSuite(TestPerson.class));
return suite;
}

Bây giờ khi bạn chạy test case này, bạn sẽ chạy tất cả các test bên trong lớp TestGame và lớp TestPeson

Chạy các test lặp đi lặp lại
Trong một vài trường hợp, chúng ta muốn chạy một test nào đó lặp đi lặp lại nhiều lần để đo hiệu suất hay phân tích các vấn đề trục trặc. JUnit cung cấp cho chúng ta lớp junit.extension.RepeatedTest để làm được điều này. Lớp RepeatedTest giúp chúng ta thực hiện điều này một cách dễ dàng

view plaincopy to clipboardprint?
1.public static Test suite() {
2.//Chạy toàn bộ test suite 10 lần
3.return new RepeatedTest(new TestSuite(TestGame.class), 10);
4.}
public static Test suite() {
//Chạy toàn bộ test suite 10 lần
return new RepeatedTest(new TestSuite(TestGame.class), 10);
}

Tham số đầu tiên của RepeatedTest là một Test cần chạy, tham số thứ 2 là số lần lặp lại. Vì TestSuite cài đặt interface Test nên chúng ta có thể lặp lại toàn bộ test như trên. Tiếp theo là ví dụ mô tả cách xây dựng một test suite mà trong đó các test khác nhau được lặp đi lặp lại khác nhau:

view plaincopy to clipboardprint?
1.public static Test suite() {
2.TestSuite suite = new TestSuite();
3.//Lặp lại testCreateFighter 100 lần
4.suite.addTest(new RepeatedTest(new TestGame(“testCreateFighter”), 100));
5.//Chạy testSameFighters 1 lần
6.suite.addTest(new TestGame(“testSameFighters”));
7.//Lặp lại testGameInitialState 20 lần
8.suite.addTest(new RepeatedTest(new TestGame(“testGameInitialState”), 20);
9.return suite;
10.}
public static Test suite() {
TestSuite suite = new TestSuite();
//Lặp lại testCreateFighter 100 lần
suite.addTest(new RepeatedTest(new TestGame(“testCreateFighter”), 100));
//Chạy testSameFighters 1 lần
suite.addTest(new TestGame(“testSameFighters”));
//Lặp lại testGameInitialState 20 lần
suite.addTest(new RepeatedTest(new TestGame(“testGameInitialState”), 20);
return suite;
}

Test các exception
Phần tiếp đến chúng ta sẽ xem xét đến một phần test cũng quan trọng không kém trong lập trình là test các exception. Chúng ta sử dụng cặp từ khóa try/catch để bắt các exception như mong đợi, chúng ta sẽ gọi phương thức fail() khi exception chúng ta mong đợi không xảy ra. Trong ví dụ sau, constructor của lớp Person nên tung ra IllegalArgumentException khi cả 2 tham số của nó đều mang giá trị null. Test sẽ thất bại nếu nó không tung ra exception.

view plaincopy to clipboardprint?
1.public void testPassNullsToConstructor() {
2.try {
3.Person p = new Person(null, null);
4.fail(“Expected IllegalArgumentException because both args are null”);
5.}
6.catch (IllegalArgumentException expected) {
7.//Bỏ qua phần này không xử lý vì có nghĩa là test được chấp nhận
8.}
9.}
public void testPassNullsToConstructor() {
try {
Person p = new Person(null, null);
fail(“Expected IllegalArgumentException because both args are null”);
}
catch (IllegalArgumentException expected) {
//Bỏ qua phần này không xử lý vì có nghĩa là test được chấp nhận
}
}

Nói chung bạn chỉ nên sử dụng kỹ thuật này khi bạn mong đợi một exception xảy ra. Đối với các điều kiện lỗi khác bạn nên để exception chuyển sang cho JUnit. Khi đó JUnit sẽ bắt lấy và tường trình một lỗi test.

Giới thiệu một số công cụ, thư viện nguồn mở hỗ trợ việc test phần mềm
Cactus

Cactus là một framework unit testing nguồn mở dùng để test cho các đoạn mã phía bên server của Java. Đặc biệt là Cactus cho phép bạn test Servlet, JSP, và Servlet filter. Cactus thừa kế từ JUnit để cung cấp 3 lớp con của lớp junit.framework.TestCase là các lớp:

• org.apache.cactus.ServletTestCase
• org.apache.cactus.JspTestCase
• org.apache.cactus.FilterTestCase

Mỗi test case của Cactus cung cấp một chức năng đặc biệt. Cactus test thực thi trên cả client và server. Khi sử dụng Cactus bạn chỉ cần tạo một lớp thừa kế từ một trong ba lớp trên. Sau đó Cactus sẽ tạo ra và chạy 2 thể hiện của test case. Một chạy trên JVM ở phía client, cái còn lại chạy bên trong JVM của môi trường chạy servlet (servlet container) phía server. Bên client phía client cho phép HTTP headers và các tham số HTTP được thêm vào các yêu cầu đi ra. Bên phía server gọi thực thi các phương thức bên trong servlet của bạn để thực hiện bất kỳ xác nhận nào, và sau đó sẽ gởi phản hồi ngược trở lại cho phía client. Tíếp đến bên phía client xác nhận phản hồi từ bên server gởi về có chứa thông tin mong muốn hay không.

Bạn có thể download Cactus từ địa chỉ http://jakarta.apache.org/cactus

HttpUnit

HttpUnit là một thư viện nguồn mở của Java được dùng để tương tác với các server HTTP. Với HttpUnit, chương trình Java của bạn có thể truy xuất trực tiếp đến server mà không cần thiết phải sử dụng đến trình duyệt.

HttpUnit cung cấp các API để phân tích HTML, nhận thông tin của biểu mẫu trang web, theo dõi các siêu liên kết, thiết lập cookie và thực hiện các tác vụ khác có liên quan đến trình duyệt web.
Ngoài ra nó cũng gồm cả một thư viện để thao tác trực tiếp đến servlet, đôi khi không cần thiết phải khởi động web server

Thông thường chúng ta sử dụng kết hợp HttpUnit và JUnit để viết các tét. JUnit định nghĩa các framework dùng để kiểm tra, và các phương thức testXXX() của bạn sẽ sử dụng các hàm API của thư viện HttpUnit để truy cập và kiểm tra trang web

Bạn có thể download HttpUnit từ địa chỉ http://www.httpunit.org

NUnit

NUnit là một framework dành cho việc testing unit trong tất cả các ngôn ngữ .NET. Khởi đầu nó cũng được bắt đầu từ JUnit, nó là một công cụ hỗ trợ việc unit testing cho Microsoft.NET. Nó được viết hoàn toàn bằng C#

Tham khảo
http://www.junit.org
 Java eXtreme Programming Cookbook – Eric M. Burke & Brian M. Coyner, O’Reilly
 Test Driven Development By Example – Addison Wesley

Itgatevn Java Group

Xếp trong: Java, JUnit

Những cách kiếm tiền trực tuyến “dễ” nhất

kiemtienonline
kiemtienonline
15 tỷ USD – đó là số tiền mà gần đây Microsoft đã mang lại cho Facebook khi đại gia máy tính đầu tư 240 triệu USD để lấy về 1,6% cổ phần trang mạng xã hội của Mark Zuckerberg.

Một số hình thức kinh doanh trực tuyến chỉ cần bạn bỏ ra vài trăm USD mua thiết bị, tuy nhiên có những mô hình kinh doanh cần đầu tư nhiều hơn cho phần cứng và thậm chí cả một nhà kho. Một số cách làm ăn có thể khiến bạn trở thành triệu phú, cũng có thể chỉ đơn giản giúp bạn kiếm tiền uống bia với bạn bè.

“Một số người đã mơ ước lập công ty riêng nhưng đành từ bỏ giấc mơ vì thiếu nguồn vốn đầu tư”, Jim Griffith, người đứng đầu trường đại học eBay, nói. “Song Internet cho phép mọi người khởi nghiệp mà không đòi hỏi số vốn ban đầu quá lớn”.

Bạn cũng có thể thử sức – hay ít nhất cũng có thể xây dựng một vận mệnh trực tuyến cho mình. Sau đây là một số mô hình kiếm tiền cơ bản từ Internet – tất nhiên, không một mô hình nào đòi hỏi phải có những bộ não như các nhà phát triển phần mềm của Google. Tuy vậy, cần cẩn thận, một số cũng khá mạo hiểm và đòi hỏi kỹ năng CNTT.

Cửa hàng ảo

Đây là một trong những mô hình kinh doanh trực tuyến cổ nhất và phổ biến nhất. Các loại hàng hóa cao cấp (như nữ trang, xe hơi) hơi khó để “bán dạo” trên web, song các mặt hàng thông thường, từ sách vở, áo sơ mi đến phòng khách sạn đều có thể bán tốt. Đằng sau một website dễ tìm kiếm, bạn sẽ cần một nhà kho để lưu giữ hàng hóa, cũng như phần mềm giúp khách hàng hoàn thành giao dịch. Nếu không muốn “dây dưa” với “đám IT”, bạn có thể thiết lập cửa hàng ngay trên eBay và để họ xử lý các vấn đề kỹ thuật. Một số nhà bán lẻ eBay tốt nhất thu về hơn 100.000 USD/năm.

Bí quyết: bán lẻ là một ngành kinh doanh cạnh tranh cao, cả trực tuyến lẫn trực tiếp. Hãy đặt ra mục tiêu và cung cấp những dịch vụ khách hàng tốt nhất để thành công.

Brandi Ramos ở Mỹ đã làm như vậy. Ramos (có con và đã ly hôn chồng), khởi nghiệp bằng gian hàng bán lẻ trực tuyến các loại quần áo dành cho nam giới trên eBay. 3 năm sau, Ramos, 32 tuổi, đã có một cơ nghiệp kha khá với doanh thu ròng từ 25.000 – 100.000 USD/năm. Cô luôn nhắm tới cung cấp dịch vụ nhanh chóng, trả lời tất cả email trong vòng 4-6 giờ.

“Địa chỉ” ảo

Bạn có thể tiếp tục việc buôn bán trực tuyến mà không phải trả tiền thuê nhà kho. Hãy làm một địa chỉ ảo và tính tiền phí hàng tháng của các nhà bán lẻ khác (hay phí cho mỗi lần giao dịch) và mang lại cho họ cơ hội được tiếp thị sản phẩm trên trang của bạn. Hình thức kinh doanh này đã góp cho Amazon.com 28% doanh thu trong năm 2006. Craigslist là một tên tuổi khác đã ứng dụng cách làm ăn này: công ty gồm 25 nhân sự thu tiền từ các doanh nghiệp muốn đăng các loại quảng cáo rao vặt ở San Francisco, New York và Los Angeles. Tổng số lượng truy cập vào website của Craigslist là 5 tỷ.

Bà mối “ảo”

Làm mối cho những người mua và người bán trực tuyến nghe có vẻ là ý tưởng kinh doanh từ thời cuối những năm 90. Tuy nhiên, thị trường này vẫn luôn nóng. eBay đã chạy các trang đấu giá trực tuyến và hưởng một phần trong mức giá bán cuối cùng. Ngoài ra, Mfg.com cũng mang các nhà sản xuất thiết bị đến các hãng cung ứng nhỏ hơn; H2Bid.com kết nối các nhà chức trách với các hãng bán thiết bị ống nước thải.

Bí quyết: công bố tỷ lệ hoa hồng rõ ràng, ngoài ra web đấu giá cần phần mềm phức tạp hơn công việc bán lẻ trực tuyến cơ bản.

Nhà cung cấp nội dung

Nếu bạn tạo ra được nội dung thực sự giá trị, bạn sẽ có thể thu tiền từ nó? Đây là một kiểu làm ăn đang thực sự phát triển thông qua Internet. Các trang web hẹn hò như Match.com rất cần những nhà cung cấp nội dung.

Ngoài ra, đây cũng là giấc mơ của các blogger: sản xuất nội dung và sau đó thu tiền quảng cáo. Bán quảng cáo chính là nguồn thu khổng lồ của các website và tờ báo điện tử. Họ thu tiền theo 2 cách: hiển thị quảng cáo và số người click (bấm chuột) vào quảng cáo. Thiết lập một blog không đòi hỏi gì hơn một chương trình xuất bản cơ bản, một máy chủ và một phần mềm để theo dõi những lần bấm chuột vào quảng cáo. Cái khó là thu hút đủ số lượng người truy cập vào blog của bạn, làm sao hấp dẫn nhà quảng cáo để họ chịu trả tiền cho bạn.

David Hauslaib, nhà xuất bản của Jossip.com, một blog chuyên về những chuyện lá cải, nói để kiếm tiền theo cách này, trang của bạn phải thu hút ít nhất 500.000 khách truy cập mỗi tháng. Coca Cola và Sketchers là những khách hàng quảng cáo của họ.

“Những trang vàng” trên mạng

Rất đơn giản, chỉ cần thu thập một loạt những website liên quan và ngồi thu phí hàng năm của người sở hữu website, hay phí kiểu “per-click” (phí tính theo số lượng click chuột). Dĩ nhiên, bạn phải đăng tải tên tuổi của họ trên website. Một ví dụ nổi tiếng của phương thức kinh doanh này là Business.com. Đây thực sự là kiểu “Những trang vàng” (Yellow Pages) trên Internet.

Tuy vậy, kiểu kinh doanh này cần sự hỗ trợ nhiều của công nghệ. Chẳng hạn, Business.com cần một hệ thống quản lý nội dung, công nghệ tìm kiếm và cách theo dõi số lần click chuột vào quảng cáo.

Kinh doanh tên miền

Đây là kiểu làm ăn tựa như kinh doanh bất động sản. Bạn có thể mua những “mảnh đất” ảo (chính là các địa chỉ URL), và kiếm tiền từ chúng. GoDaddy.com đã bán các tên miền chưa sử dụng với giá dưới 10 USD/“mảnh”. Để hấp dẫn người mua, hãy chạy thử nghiệm trước nhằm đảm bảo các từ khóa nhất định nào đó được tìm kiếm rất nhiều, sau đó bạn có thể chứng minh khả năng URL của bạn sẽ xuất hiện trên Google hoặc Yahoo!.

Bí quyết: những tên miền tốt nhất là những tên ngắn, dễ đọc, dễ nhớ và cụ thể.

Với những phương pháp kiếm tiền trên, bạn có thể thử vận mệnh của mình trên Internet.

Theo ICTnews

Vòng đời của một tên miền quốc tế !!!

Vòng đời của một tên miền quốc tế

Vòng đời của một tên miền quốc tế? Các giai đoạn trong vòng đời của tên miền. Bài viết này giúp quý vị hiểu được vòng đời của một tên miền quốc tế, qua đó sẽ có khái niệm rõ ràng hơn trong việc đăng ký, mua bán tên miền và bảo vệ tên miền của mình.

1. Available

Giai đoạn này tên miền chưa được ai đăng ký. Bạn có thể đăng ký tên miền với điều kiện tên miền hợp lệ.

Tên miền hợp lệ phải có điều kiện gì?

1. Chỉ có thể bao gồm chữ cái, chữ số hoặc dấu –
2. Chiều dài tối đa của tên miền là 64 ký tự
3. Ví dụ: abcxyz.com, 38681888.com, alo123.net, call-me-123.net

2. Registered

– Giai đoạn này là tên miền đã được đăng ký, tên miền có thể được sử dụng làm tên website, e-mail, …
– Giai đoạn này kéo dài từ 1 – 10 năm.

3. Expired

Thời điểm hết hạn của tên miền

4. Auto-Renew

– Giai đoạn này có thể hiểu là giai đoạn tên miền đã hết hạn, nhưng vẫn có thể cứu được tên miền. Thường giai đoạn này DNS sẽ bị Registrar đổi nên website, email thường bị gián đoạn hoạt động. Mặc dù thông tin quản lý tên miền vẫn còn giữ nguyên.
– Thời gian này là thời gian có thể gia hạn tên miền để tên miền quay lại giai đọan Registered

Tại sao 0 – 45 ngày?

– Giai đoạn này có thể giản từ 0 – 45 ngày, do ICANN quy định. Registrar có thể dựa vào đó để ấn định con số ngày cụ thể.
– Thường các Registrar ấn định thời gian giai đoạn này là 40 ngày.

5.Redemption

– Giai đoạn này có thể coi tên miền đã chết, toàn bộ thông tin quản trị của tên miền đã bị xoá, mọi hoạt động dựa trên tên miền (web, mail, …) đều bị chấm dứt.
– Tên miền có thể cứu bằng cách liên hệ trực tiếp đến Registrar để yêu cầu chuộc tên miền, chi phí phải trả = phí chuộc + phí gia hạn tên miền tối thiểu 1 năm
– Chi phí phải trả = phí chuộc + phí gia hạn tên miền tối thiểu 1 năm
– Giai đoạn này kéo dài 30 ngày.

Phí chuộc? Phí gia hạn?

– Là phí trả cho Registrar để chuộc lại tên miền đã vào trạng thái Redemption
– Tuỳ thuộc vào quy định của Registrar mà phí chuộc có thể là: 100, 120, 140, 175, 200$, …
– Sau khi chuộc được tên miền, tên miền cần được gia hạn từ 1 – 10 năm để quay lại trạng thái Registered.

6.Pending Delete

1. Giai đoạn này tên miền đã chết hoàn toàn, không có khả năng cứu.
2. Thời gian kéo dài 5 ngày

7.Released (Available)

– Tên miền trở về trạng thái ban đầu Available, chờ được đăng trở lại. Bắt đầu một vòng đời mới.
– Tên miền có giá trị rất dễ bị mất vĩnh viễn
– Tên miền có lượng truy cập nhiều thường được các bộ máy săn tên miền “quan tâm”.
– Khi tên miền vừa Release mà chủ tên miền không kịp đăng ký lại thì sẽ bị bộ máy kia sẽ nhanh tay đăng ký trước.

Chúc bạn thành công – http://www.ticsoft.com (Nguồn: sưu tầm

Blog tại WordPress.com.

Up ↑