Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
oleh Microsoft
Dalam iterasi keenam ini, kami menambahkan fungsionalitas baru ke aplikasi kami dengan menulis pengujian unit terlebih dahulu dan menulis kode terhadap pengujian unit. Dalam perulangan ini, kami menambahkan grup kontak.
Membangun Manajemen Kontak ASP.NET Aplikasi MVC (VB)
Dalam rangkaian tutorial ini, kami membangun seluruh aplikasi Manajemen Kontak dari awal hingga akhir. Aplikasi Contact Manager memungkinkan Anda menyimpan informasi kontak - nama, nomor telepon, dan alamat email - untuk daftar orang.
Kami membangun aplikasi melalui beberapa iterasi. Dengan setiap iterasi, kami secara bertahap meningkatkan aplikasi. Tujuan dari pendekatan perulangan ganda ini adalah untuk memungkinkan Anda memahami alasan setiap perubahan.
Iterasi #1 - Buat aplikasi. Dalam iterasi pertama, kami membuat Contact Manager dengan cara yang paling sederhana. Kami menambahkan dukungan untuk operasi database dasar: Buat, Baca, Perbarui, dan Hapus (CRUD).
Iterasi #2 - Membuat aplikasi terlihat bagus. Dalam perulangan ini, kami meningkatkan tampilan aplikasi dengan memodifikasi halaman master tampilan ASP.NET MVC default dan lembar gaya bertingkat.
Iterasi #3 - Tambahkan validasi formulir. Dalam iterasi ketiga, kami menambahkan validasi formulir dasar. Kami mencegah orang mengirimkan formulir tanpa melengkapi bidang formulir yang diperlukan. Kami juga memvalidasi alamat email dan nomor telepon.
Iterasi #4 - Buat aplikasi digabungkan secara longgar. Dalam iterasi keempat ini, kami memanfaatkan beberapa pola desain perangkat lunak untuk mempermudah pemeliharaan dan modifikasi aplikasi Contact Manager. Misalnya, kami merefaktor aplikasi kami untuk menggunakan pola Repositori dan pola Injeksi Dependensi.
Iterasi #5 - Membuat pengujian unit. Dalam iterasi kelima, kami membuat aplikasi kami lebih mudah dirawat dan dimodifikasi dengan menambahkan pengujian unit. Kami meniru kelas model data kami dan membangun pengujian unit untuk pengontrol dan logika validasi kami.
Iterasi #6 - Gunakan pengembangan berbasis pengujian. Dalam iterasi keenam ini, kami menambahkan fungsionalitas baru ke aplikasi kami dengan menulis pengujian unit terlebih dahulu dan menulis kode terhadap pengujian unit. Dalam perulangan ini, kami menambahkan grup kontak.
Iterasi #7 - Tambahkan fungsionalitas Ajax. Dalam iterasi ketujuh, kami meningkatkan responsivitas dan performa aplikasi kami dengan menambahkan dukungan untuk Ajax.
Perulangan Ini
Dalam iterasi sebelumnya dari aplikasi Contact Manager, kami membuat pengujian unit untuk menyediakan jaring pengaman untuk kode kami. Motivasi untuk membuat pengujian unit adalah untuk membuat kode kami lebih tangguh untuk diubah. Dengan pengujian unit di tempat, kita dapat dengan senang hati membuat perubahan pada kode kita dan segera tahu apakah kita telah merusak fungsionalitas yang ada.
Dalam iterasi ini, kami menggunakan pengujian unit untuk tujuan yang sama sekali berbeda. Dalam perulangan ini, kami menggunakan pengujian unit sebagai bagian dari filosofi desain aplikasi yang disebut pengembangan berbasis pengujian. Saat Anda mempraktikkan pengembangan berbasis pengujian, Anda menulis pengujian terlebih dahulu lalu menulis kode terhadap pengujian.
Lebih tepatnya, saat mempraktikkan pengembangan berbasis pengujian, ada tiga langkah yang Anda selesaikan saat membuat kode (Merah/ Hijau/Refaktor):
- Menulis pengujian unit yang gagal (Merah)
- Menulis kode yang lulus uji unit (Hijau)
- Refaktor kode Anda (Refaktor)
Pertama, Anda menulis pengujian unit. Pengujian unit harus mengekspresikan niat Anda tentang bagaimana Anda mengharapkan kode Anda berulah. Ketika Anda pertama kali membuat pengujian unit, pengujian unit harus gagal. Pengujian harus gagal karena Anda belum menulis kode aplikasi apa pun yang memenuhi pengujian.
Selanjutnya, Anda menulis kode yang cukup agar pengujian unit lulus. Tujuannya adalah untuk menulis kode dengan cara yang paling lazim, paling miring, dan tercepat. Anda tidak boleh membuang-buang waktu untuk memikirkan arsitektur aplikasi Anda. Sebagai gantinya, Anda harus fokus pada penulisan jumlah kode minimal yang diperlukan untuk memenuhi niat yang dinyatakan oleh pengujian unit.
Akhirnya, setelah Anda menulis kode yang cukup, Anda dapat mundur dan mempertimbangkan arsitektur keseluruhan aplikasi Anda. Dalam langkah ini, Anda menulis ulang (refaktor) kode Anda dengan memanfaatkan pola desain perangkat lunak -- seperti pola repositori -- sehingga kode Anda lebih dapat dipertahankan. Anda dapat dengan takut menulis ulang kode Anda dalam langkah ini karena kode Anda dicakup oleh pengujian unit.
Ada banyak manfaat yang dihasilkan dari mempraktikkan pengembangan berbasis pengujian. Pertama, pengembangan berbasis pengujian memaksa Anda untuk fokus pada kode yang sebenarnya perlu ditulis. Karena Anda terus-menerus fokus pada hanya menulis kode yang cukup untuk lulus tes tertentu, Anda dicegah berkeliaran ke gulma dan menulis sejumlah besar kode yang tidak akan pernah Anda gunakan.
Kedua, metodologi desain "uji pertama" memaksa Anda menulis kode dari perspektif bagaimana kode Anda akan digunakan. Dengan kata lain, saat mempraktikkan pengembangan berbasis pengujian, Anda terus-menerus menulis pengujian Anda dari perspektif pengguna. Oleh karena itu, pengembangan berbasis pengujian dapat menghasilkan API yang lebih bersih dan lebih dapat dipahami.
Akhirnya, pengembangan berbasis pengujian memaksa Anda untuk menulis pengujian unit sebagai bagian dari proses normal penulisan aplikasi. Saat tenggat waktu proyek mendekat, pengujian biasanya merupakan hal pertama yang keluar jendela. Ketika mempraktikkan pengembangan berbasis pengujian, di sisi lain, Anda lebih mungkin berbudi luhur tentang pengujian unit penulisan karena pengembangan berbasis pengujian membuat pengujian unit menjadi pusat proses membangun aplikasi.
Catatan
Untuk mempelajari lebih lanjut tentang pengembangan berbasis pengujian, saya sarankan Anda membaca buku Michael Feathers Bekerja Secara Efektif dengan Kode Warisan.
Dalam perulangan ini, kami menambahkan fitur baru ke aplikasi Contact Manager kami. Kami menambahkan dukungan untuk Grup Kontak. Anda bisa menggunakan Grup Kontak untuk menata kontak Anda ke dalam kategori seperti grup Bisnis dan Teman.
Kami akan menambahkan fungsionalitas baru ini ke aplikasi kami dengan mengikuti proses pengembangan berbasis pengujian. Kami akan menulis pengujian unit terlebih dahulu dan kami akan menulis semua kode kami terhadap tes ini.
Apa yang Akan Diuji
Seperti yang kita bahas dalam iterasi sebelumnya, Anda biasanya tidak menulis pengujian unit untuk logika akses data atau melihat logika. Anda tidak menulis pengujian unit untuk logika akses data karena mengakses database adalah operasi yang relatif lambat. Anda tidak menulis pengujian unit untuk melihat logika karena mengakses tampilan memerlukan pemutaran server web yang merupakan operasi yang relatif lambat. Anda tidak boleh menulis pengujian unit kecuali tes dapat dijalankan berulang-ulang dengan sangat cepat
Karena pengembangan berbasis pengujian didorong oleh pengujian unit, kami awalnya fokus pada penulisan pengontrol dan logika bisnis. Kami menghindari menyentuh database atau tampilan. Kami tidak akan memodifikasi database atau membuat tampilan kami sampai akhir tutorial ini. Kita mulai dengan apa yang dapat diuji.
Membuat Cerita Pengguna
Saat mempraktikkan pengembangan berbasis pengujian, Anda selalu mulai dengan menulis tes. Ini segera menimbulkan pertanyaan: Bagaimana Anda memutuskan tes apa yang akan ditulis terlebih dahulu? Untuk menjawab pertanyaan ini, Anda harus menulis sekumpulan cerita pengguna.
Cerita pengguna adalah deskripsi yang sangat singkat (biasanya satu kalimat) tentang persyaratan perangkat lunak. Ini harus berupa deskripsi non-teknis tentang persyaratan yang ditulis dari perspektif pengguna.
Berikut adalah kumpulan cerita pengguna yang menjelaskan fitur yang diperlukan oleh fungsionalitas Grup Kontak baru:
- Pengguna dapat melihat daftar grup kontak.
- Pengguna dapat membuat grup kontak baru.
- Pengguna dapat menghapus grup kontak yang sudah ada.
- Pengguna dapat memilih grup kontak saat membuat kontak baru.
- Pengguna dapat memilih grup kontak saat mengedit kontak yang sudah ada.
- Daftar grup kontak ditampilkan dalam tampilan Indeks.
- Saat pengguna mengklik grup kontak, daftar kontak yang cocok akan ditampilkan.
Perhatikan bahwa daftar cerita pengguna ini benar-benar dapat dimengerti oleh pelanggan. Tidak ada penyebutan detail implementasi teknis.
Saat dalam proses membangun aplikasi Anda, serangkaian cerita pengguna dapat menjadi lebih halus. Anda dapat memecah cerita pengguna menjadi beberapa cerita (persyaratan). Misalnya, Anda mungkin memutuskan bahwa membuat grup kontak baru harus melibatkan validasi. Mengirimkan grup kontak tanpa nama harus mengembalikan kesalahan validasi.
Setelah membuat daftar cerita pengguna, Anda siap untuk menulis pengujian unit pertama Anda. Kita akan mulai dengan membuat pengujian unit untuk melihat daftar grup kontak.
Mencantumkan Grup Kontak
Kisah pengguna pertama kami adalah bahwa pengguna harus dapat melihat daftar grup kontak. Kita perlu mengekspresikan cerita ini dengan tes.
Buat pengujian unit baru dengan mengklik kanan folder Pengontrol di proyek ContactManager.Tests, memilih Tambahkan, Pengujian Baru, dan pilih templat Pengujian Unit (lihat Gambar 1). Beri nama pengujian unit baru GroupControllerTest.vb dan klik tombol OK .
Gambar 01: Menambahkan pengujian unit GroupControllerTest (Klik untuk melihat gambar ukuran penuh)
Pengujian unit pertama kami terkandung dalam Listing 1. Pengujian ini memverifikasi bahwa metode Index() pengontrol Grup mengembalikan sekumpulan Grup. Pengujian memverifikasi bahwa kumpulan Grup dikembalikan dalam data tampilan.
Daftar 1 - Controllers\GroupControllerTest.vb
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports System.Web.Mvc
<TestClass()> _
Public Class GroupControllerTest
<TestMethod()> _
Public Sub Index()
' Arrange
Dim controller = New GroupController()
' Act
Dim result = CType(controller.Index(), ViewResult)
' Assert
Assert.IsInstanceOfType(result.ViewData.Model, GetType(IEnumerable(Of Group)))
End Sub
End Class
Saat pertama kali mengetik kode di Listing 1 di Visual Studio, Anda akan mendapatkan banyak garis berlekuk merah. Kami belum membuat kelas GroupController atau Group.
Pada titik ini, kita bahkan tidak dapat membangun aplikasi kita sehingga kita tidak dapat menjalankan pengujian unit pertama kita. Itu bagus. Itu dihitung sebagai tes yang gagal. Oleh karena itu, kita sekarang memiliki izin untuk mulai menulis kode aplikasi. Kita perlu menulis kode yang cukup untuk menjalankan tes kita.
Kelas Pengontrol grup di Listing 2 berisi kode minimum yang diperlukan untuk lulus pengujian unit. Tindakan Index() mengembalikan daftar Grup yang dikodekan secara statis (kelas Grup ditentukan dalam Daftar 3).
Daftar 2 - Controllers\GroupController.vb
Public Class GroupController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Dim groups = new List(Of Group)
Return View(groups)
End Function
End Class
Daftar 3 - Models\Group.vb
Public Class Group
End Class
Setelah kami menambahkan kelas GroupController dan Group ke proyek kami, pengujian unit pertama kami berhasil diselesaikan (lihat Gambar 2). Kami telah melakukan pekerjaan minimum yang diperlukan untuk lulus tes. Sudah waktunya untuk merayakan.
Gambar 02: Sukses! (Klik untuk melihat gambar ukuran penuh)
Membuat Grup Kontak
Sekarang kita dapat melanjutkan ke cerita pengguna kedua. Kita harus dapat membuat grup kontak baru. Kita perlu mengekspresikan niat ini dengan tes.
Pengujian di Daftar 4 memverifikasi bahwa memanggil metode Create() dengan Grup baru menambahkan Grup ke daftar Grup yang dikembalikan oleh metode Index(). Dengan kata lain, jika saya membuat grup baru maka saya harus bisa mendapatkan kembali Grup baru dari daftar Grup yang dikembalikan oleh metode Index().
Daftar 4 - Controllers\GroupControllerTest.vb
<TestMethod> _
Public Sub Create()
' Arrange
Dim controller = New GroupController()
' Act
Dim groupToCreate = New Group()
controller.Create(groupToCreate)
' Assert
Dim result = CType(controller.Index(), ViewResult)
Dim groups = CType(result.ViewData.Model, IEnumerable(Of Group))
CollectionAssert.Contains(groups.ToList(), groupToCreate)
End Sub
Pengujian di Daftar 4 memanggil metode Buat() pengontrol Grup dengan Grup kontak baru. Selanjutnya, pengujian memverifikasi bahwa memanggil metode Group controller Index() mengembalikan Grup baru dalam data tampilan.
Pengontrol Grup yang dimodifikasi di Daftar 5 berisi perubahan minimum yang diperlukan untuk lulus pengujian baru.
Daftar 5 - Controllers\GroupController.vb
Public Class GroupController
Inherits Controller
Private _groups As IList(Of Group) = New List(Of Group)()
Public Function Index() As ActionResult
Return View(_groups)
End Function
Public Function Create(ByVal groupToCreate As Group) As ActionResult
_groups.Add(groupToCreate)
Return RedirectToAction("Index")
End Function
End Class
Pengontrol Grup di Daftar 5 memiliki tindakan Create() baru. Tindakan ini menambahkan Grup ke kumpulan Grup. Perhatikan bahwa tindakan Index() telah dimodifikasi untuk mengembalikan konten kumpulan Grup.
Sekali lagi, kami telah melakukan jumlah minimum pekerjaan yang diperlukan untuk lulus uji unit. Setelah kami membuat perubahan ini pada pengontrol Grup, semua pengujian unit kami lulus.
Menambahkan Validasi
Persyaratan ini tidak dinyatakan secara eksplisit dalam cerita pengguna. Namun, wajar untuk mengharuskan Grup memiliki nama. Jika tidak, mengatur kontak ke dalam Grup tidak akan sangat berguna.
Daftar 6 berisi pengujian baru yang mengekspresikan niat ini. Pengujian ini memverifikasi bahwa mencoba membuat Grup tanpa memberikan nama menghasilkan pesan kesalahan validasi dalam status model.
Daftar 6 - Controllers\GroupControllerTest.vb
<TestMethod> _
Public Sub CreateRequiredName()
' Arrange
Dim controller = New GroupController()
' Act
Dim groupToCreate As New Group()
groupToCreate.Name = String.Empty
Dim result = CType(controller.Create(groupToCreate), ViewResult)
' Assert
Dim [error] = result.ViewData.ModelState("Name").Errors(0)
Assert.AreEqual("Name is required.", [error].ErrorMessage)
End Sub
Untuk memenuhi pengujian ini, kita perlu menambahkan properti Nama ke kelas Grup kita (lihat Daftar 7). Selain itu, kita perlu menambahkan sedikit logika validasi ke tindakan Buat() pengontrol Grup (lihat Daftar 8).
Daftar 7 - Models\Group.vb
Public Class Group
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
Daftar 8 - Controllers\GroupController.vb
Public Function Create(ByVal groupToCreate As Group) As ActionResult
' Validation logic
If groupToCreate.Name.Trim().Length = 0 Then
ModelState.AddModelError("Name", "Name is required.")
Return View("Create")
End If
' Database logic
_groups.Add(groupToCreate)
Return RedirectToAction("Index")
End Function
Perhatikan bahwa tindakan Buat() pengontrol Grup sekarang berisi validasi dan logika database. Saat ini, database yang digunakan oleh pengontrol Grup tidak lebih dari koleksi dalam memori.
Waktu untuk Refaktor
Langkah ketiga dalam Merah/Hijau/Refaktor adalah bagian Refaktor. Pada titik ini, kita perlu mundur dari kode kita dan mempertimbangkan bagaimana kita dapat merefaktor aplikasi kita untuk meningkatkan desainnya. Tahap Refaktor adalah tahap di mana kami berpikir keras tentang cara terbaik untuk menerapkan prinsip dan pola desain perangkat lunak.
Kami bebas untuk memodifikasi kode kami dengan cara apa pun yang kami pilih untuk meningkatkan desain kode. Kami memiliki jaring pengaman pengujian unit yang mencegah kami merusak fungsionalitas yang ada.
Saat ini, pengontrol Grup kami berantakan dari perspektif desain perangkat lunak yang baik. Pengontrol Grup berisi berantakan kusut validasi dan kode akses data. Untuk menghindari pelanggaran Prinsip Tanggung Jawab Tunggal, kita perlu memisahkan kekhawatiran ini ke dalam kelas yang berbeda.
Kelas pengontrol Grup kami yang direfaktor terkandung dalam Daftar 9. Pengontrol telah dimodifikasi untuk menggunakan lapisan layanan ContactManager. Ini adalah lapisan layanan yang sama dengan yang kami gunakan dengan pengontrol Kontak.
Daftar 10 berisi metode baru yang ditambahkan ke lapisan layanan ContactManager untuk mendukung validasi, daftar, dan pembuatan grup. Antarmuka IContactManagerService diperbarui untuk menyertakan metode baru.
Daftar 11 berisi kelas FakeContactManagerRepository baru yang mengimplementasikan antarmuka IContactManagerRepository. Tidak seperti kelas EntityContactManagerRepository yang juga mengimplementasikan antarmuka IContactManagerRepository, kelas FakeContactManagerRepository baru kami tidak berkomunikasi dengan database. Kelas FakeContactManagerRepository menggunakan koleksi dalam memori sebagai proksi untuk database. Kami akan menggunakan kelas ini dalam pengujian unit kami sebagai lapisan repositori palsu.
Daftar 9 - Controllers\GroupController.vb
Public Class GroupController
Inherits Controller
Private _service As IContactManagerService
Public Sub New()
_service = New ContactManagerService(New ModelStateWrapper(Me.ModelState))
End Sub
Public Sub New(ByVal service As IContactManagerService)
_service = service
End Sub
Public Function Index() As ActionResult
Return View(_service.ListGroups())
End Function
Public Function Create(ByVal groupToCreate As Group) As ActionResult
If _service.CreateGroup(groupToCreate) Then
Return RedirectToAction("Index")
End If
Return View("Create")
End Function
End Class
Daftar 10 - Controllers\ContactManagerService.vb
Public Function ValidateGroup(ByVal groupToValidate As Group) As Boolean
If groupToValidate.Name.Trim().Length = 0 Then
_validationDictionary.AddError("Name", "Name is required.")
End If
Return _validationDictionary.IsValid
End Function
Public Function CreateGroup(ByVal groupToCreate As Group) As Boolean Implements IContactManagerService.CreateGroup
' Validation logic
If Not ValidateGroup(groupToCreate) Then
Return False
End If
' Database logic
Try
_repository.CreateGroup(groupToCreate)
Catch
Return False
End Try
Return True
End Function
Public Function ListGroups() As IEnumerable(Of Group) Implements IContactManagerService.ListGroups
Return _repository.ListGroups()
End Function
Daftar 11 - Controllers\FakeContactManagerRepository.vb
Public Class FakeContactManagerRepository
Implements IContactManagerRepository
Private _groups As IList(Of Group) = New List(Of Group)()
#Region "IContactManagerRepository Members"
' Group methods
Public Function CreateGroup(ByVal groupToCreate As Group) As Group Implements IContactManagerRepository.CreateGroup
_groups.Add(groupToCreate)
Return groupToCreate
End Function
Public Function ListGroups() As IEnumerable(Of Group) Implements IContactManagerRepository.ListGroups
Return _groups
End Function
' Contact methods
Public Function CreateContact(ByVal contactToCreate As Contact) As Contact Implements IContactManagerRepository.CreateContact
Throw New NotImplementedException()
End Function
Public Sub DeleteContact(ByVal contactToDelete As Contact) Implements IContactManagerRepository.DeleteContact
Throw New NotImplementedException()
End Sub
Public Function EditContact(ByVal contactToEdit As Contact) As Contact Implements IContactManagerRepository.EditContact
Throw New NotImplementedException()
End Function
Public Function GetContact(ByVal id As Integer) As Contact Implements IContactManagerRepository.GetContact
Throw New NotImplementedException()
End Function
Public Function ListContacts() As IEnumerable(Of Contact) Implements IContactManagerRepository.ListContacts
Throw New NotImplementedException()
End Function
#End Region
End Class
Memodifikasi antarmuka IContactManagerRepository memerlukan penggunaan untuk mengimplementasikan metode CreateGroup() dan ListGroups() di kelas EntityContactManagerRepository. Cara termalukan dan tercepat untuk melakukan ini adalah dengan menambahkan metode ganja yang terlihat seperti ini:
Public Function CreateGroup(groupToCreate As Group) As Group Implements IContactManagerRepository.CreateGroup
throw New NotImplementedException()
End Function
Public Function ListGroups() As IEnumerable(Of Group) Implements IContactManagerRepository.ListGroups
throw New NotImplementedException()
End Function
Akhirnya, perubahan pada desain aplikasi kami mengharuskan kami untuk melakukan beberapa modifikasi pada pengujian unit kami. Kita sekarang perlu menggunakan FakeContactManagerRepository saat melakukan pengujian unit. Kelas GroupControllerTest yang diperbarui terkandung dalam Listing 12.
Daftar 12 - Controllers\GroupControllerTest.vb
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports System.Web.Mvc
<TestClass()> _
Public Class GroupControllerTest
Private _repository As IContactManagerRepository
Private _modelState As ModelStateDictionary
Private _service As IContactManagerService
<TestInitialize()> _
Public Sub Initialize()
_repository = New FakeContactManagerRepository()
_modelState = New ModelStateDictionary()
_service = New ContactManagerService(New ModelStateWrapper(_modelState), _repository)
End Sub
<TestMethod()> _
Public Sub Index()
' Arrange
Dim controller = New GroupController(_service)
' Act
Dim result = CType(controller.Index(), ViewResult)
' Assert
Assert.IsInstanceOfType(result.ViewData.Model, GetType(IEnumerable(Of Group)))
End Sub
<TestMethod()> _
Public Sub Create()
' Arrange
Dim controller = New GroupController(_service)
' Act
Dim groupToCreate = New Group()
groupToCreate.Name = "Business"
controller.Create(groupToCreate)
' Assert
Dim result = CType(controller.Index(), ViewResult)
Dim groups = CType(result.ViewData.Model, IEnumerable(Of Group))
CollectionAssert.Contains(groups.ToList(), groupToCreate)
End Sub
<TestMethod()> _
Public Sub CreateRequiredName()
' Arrange
Dim controller = New GroupController(_service)
' Act
Dim groupToCreate = New Group()
groupToCreate.Name = String.Empty
Dim result = CType(controller.Create(groupToCreate), ViewResult)
' Assert
Dim nameError = _modelState("Name").Errors(0)
Assert.AreEqual("Name is required.", nameError.ErrorMessage)
End Sub
End Class
Setelah kita membuat semua perubahan ini, sekali lagi, semua pengujian unit kita lulus. Kami telah menyelesaikan seluruh siklus Merah/Hijau/Refaktor. Kami telah menerapkan dua cerita pengguna pertama. Kami sekarang memiliki pengujian unit pendukung untuk persyaratan yang dinyatakan dalam cerita pengguna. Menerapkan sisa cerita pengguna melibatkan pengulangan siklus Merah/Hijau/Refaktor yang sama.
Memodifikasi Database kami
Sayangnya, meskipun kami telah memenuhi semua persyaratan yang dinyatakan oleh pengujian unit kami, pekerjaan kami tidak dilakukan. Kita masih perlu memodifikasi database kita.
Kita perlu membuat tabel database Grup baru. Ikuti langkah-langkah berikut:
- Di jendela Penjelajah Server, klik kanan folder Tabel dan pilih opsi menu Tambahkan Tabel Baru.
- Masukkan dua kolom yang dijelaskan di bawah ini dalam Designer Tabel.
- Tandai kolom Id sebagai kunci primer dan kolom Identitas.
- Simpan tabel baru dengan nama Grup dengan mengklik ikon floppy.
Nama Kolom | Jenis Data | Perbolehkan Null |
---|---|---|
Id | int | FALSE |
Nama | nvarchar(50) | Salah |
Selanjutnya, kita perlu menghapus semua data dari tabel Kontak (jika tidak, kita tidak akan dapat membuat hubungan antara tabel Kontak dan Grup). Ikuti langkah-langkah berikut:
- Klik kanan tabel Kontak dan pilih opsi menu Perlihatkan Data Tabel.
- Hapus semua baris.
Selanjutnya, kita perlu menentukan hubungan antara tabel database Grup dan tabel database Kontak yang sudah ada. Ikuti langkah-langkah berikut:
- Klik dua kali tabel Kontak di jendela Penjelajah Server untuk membuka Designer Tabel.
- Tambahkan kolom bilangan bulat baru ke tabel Kontak bernama GroupId.
- Klik tombol Hubungan untuk membuka dialog Hubungan Kunci Asing (lihat Gambar 3).
- Klik tombol Tambahkan.
- Klik tombol elipsis yang muncul di samping tombol Spesifikasi Tabel dan Kolom.
- Dalam dialog Tabel dan Kolom, pilih Grup sebagai tabel kunci utama dan Id sebagai kolom kunci utama. Pilih Kontak sebagai tabel kunci asing dan GroupId sebagai kolom kunci asing (lihat Gambar 4). Klik tombol Ok.
- Di bawah SISIPKAN dan PERBARUI Spesifikasi, pilih nilai Kaskade untuk Hapus Aturan.
- Klik tombol Tutup untuk menutup dialog Hubungan Kunci Asing.
- Klik tombol Simpan untuk menyimpan perubahan ke tabel Kontak.
Gambar 03: Membuat hubungan tabel database (Klik untuk melihat gambar ukuran penuh)
Gambar 04: Menentukan hubungan tabel (Klik untuk melihat gambar ukuran penuh)
Memperbarui Model Data kami
Selanjutnya, kita perlu memperbarui model data kita untuk mewakili tabel database baru. Ikuti langkah-langkah berikut:
- Klik dua kali file ContactManagerModel.edmx di folder Model untuk membuka Designer Entitas.
- Klik kanan permukaan Designer dan pilih opsi menu Perbarui Model dari Database.
- Di Panduan Pembaruan, pilih tabel Grup dan klik tombol Selesai (lihat Gambar 5).
- Klik kanan entitas Grup dan pilih opsi menu Ganti Nama. Ubah nama entitas Grup menjadi Grup (tunggal).
- Klik kanan properti navigasi Grup yang muncul di bagian bawah entitas Kontak. Ubah nama properti navigasi Grup menjadi Grup (tunggal).
Gambar 05: Memperbarui model Kerangka Kerja Entitas dari database (Klik untuk melihat gambar ukuran penuh)
Setelah Anda menyelesaikan langkah-langkah ini, model data Anda akan mewakili tabel Kontak dan Grup. Designer Entitas harus menampilkan kedua entitas (lihat Gambar 6).
Gambar 06: Entitas Designer menampilkan Grup dan Kontak(Klik untuk melihat gambar ukuran penuh)
Membuat Kelas Repositori kami
Selanjutnya, kita perlu mengimplementasikan kelas repositori kita. Selama iterasi ini, kami menambahkan beberapa metode baru ke antarmuka IContactManagerRepository sambil menulis kode untuk memenuhi pengujian unit kami. Versi akhir antarmuka IContactManagerRepository terkandung dalam Listing 14.
Daftar 14 - Model\IContactManagerRepository.vb
Public Interface IContactManagerRepository
' Contact methods
Function CreateContact(ByVal groupId As Integer, ByVal contactToCreate As Contact) As Contact
Sub DeleteContact(ByVal contactToDelete As Contact)
Function EditContact(ByVal groupId As Integer, ByVal contactToEdit As Contact) As Contact
Function GetContact(ByVal id As Integer) As Contact
' Group methods
Function CreateGroup(ByVal groupToCreate As Group) As Group
Function ListGroups() As IEnumerable(Of Group)
Function GetGroup(ByVal groupId As Integer) As Group
Function GetFirstGroup() As Group
Sub DeleteGroup(ByVal groupToDelete As Group)
End Interface
Kami belum benar-benar menerapkan salah satu metode yang terkait dengan bekerja dengan grup kontak di kelas EntityContactManagerRepository kami yang sebenarnya. Saat ini, kelas EntityContactManagerRepository memiliki metode stub untuk setiap metode grup kontak yang tercantum di antarmuka IContactManagerRepository. Misalnya, metode ListGroups() saat ini terlihat seperti ini:
Public Function ListGroups() As IEnumerable(Of Group) Implements IContactManagerRepository.ListGroups
throw New NotImplementedException()
End Function
Metode stub memungkinkan kami untuk mengkompilasi aplikasi kami dan lulus pengujian unit. Namun, sekarang saatnya untuk benar-benar menerapkan metode ini. Versi akhir kelas EntityContactManagerRepository terkandung dalam Listing 13.
Daftar 13 - Models\EntityContactManagerRepository.vb
Public Class EntityContactManagerRepository
Implements IContactManagerRepository
Private _entities As New ContactManagerDBEntities()
' Contact methods
Public Function GetContact(ByVal id As Integer) As Contact Implements IContactManagerRepository.GetContact
Return (From c In _entities.ContactSet.Include("Group") _
Where c.Id = id _
Select c).FirstOrDefault()
End Function
Public Function CreateContact(ByVal groupId As Integer, ByVal contactToCreate As Contact) As Contact Implements IContactManagerRepository.CreateContact
' Associate group with contact
contactToCreate.Group = GetGroup(groupId)
' Save new contact
_entities.AddToContactSet(contactToCreate)
_entities.SaveChanges()
Return contactToCreate
End Function
Public Function EditContact(ByVal groupId As Integer, ByVal contactToEdit As Contact) As Contact Implements IContactManagerRepository.EditContact
' Get original contact
Dim originalContact = GetContact(contactToEdit.Id)
' Update with new group
originalContact.Group = GetGroup(groupId)
' Save changes
_entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit)
_entities.SaveChanges()
Return contactToEdit
End Function
Public Sub DeleteContact(ByVal contactToDelete As Contact) Implements IContactManagerRepository.DeleteContact
Dim originalContact = GetContact(contactToDelete.Id)
_entities.DeleteObject(originalContact)
_entities.SaveChanges()
End Sub
' Group methods
Public Function CreateGroup(ByVal groupToCreate As Group) As Group Implements IContactManagerRepository.CreateGroup
_entities.AddToGroupSet(groupToCreate)
_entities.SaveChanges()
Return groupToCreate
End Function
Public Function ListGroups() As IEnumerable(Of Group) Implements IContactManagerRepository.ListGroups
Return _entities.GroupSet.ToList()
End Function
Public Function GetFirstGroup() As Group Implements IContactManagerRepository.GetFirstGroup
Return _entities.GroupSet.Include("Contacts").FirstOrDefault()
End Function
Public Function GetGroup(ByVal id As Integer) As Group Implements IContactManagerRepository.GetGroup
Return (From g In _entities.GroupSet.Include("Contacts") _
Where g.Id = id _
Select g).FirstOrDefault()
End Function
Public Sub DeleteGroup(ByVal groupToDelete As Group) Implements IContactManagerRepository.DeleteGroup
Dim originalGroup = GetGroup(groupToDelete.Id)
_entities.DeleteObject(originalGroup)
_entities.SaveChanges()
End Sub
End Class
Membuat Tampilan
ASP.NET aplikasi MVC saat Anda menggunakan mesin tampilan ASP.NET default. Jadi, Anda tidak membuat tampilan sebagai respons terhadap pengujian unit tertentu. Namun, karena aplikasi tidak akan berguna tanpa tampilan, kami tidak dapat menyelesaikan iterasi ini tanpa membuat dan memodifikasi tampilan yang terkandung dalam aplikasi Contact Manager.
Kita perlu membuat tampilan baru berikut untuk mengelola grup kontak (lihat Gambar 7):
- Views\Group\Index.aspx - Menampilkan daftar grup kontak
- Views\Group\Delete.aspx - Menampilkan formulir konfirmasi untuk menghapus grup kontak
Gambar 07: Tampilan Indeks Grup (Klik untuk melihat gambar ukuran penuh)
Kita perlu mengubah tampilan yang sudah ada berikut ini sehingga mereka menyertakan grup kontak:
- Views\Home\Create.aspx
- Views\Home\Edit.aspx
- Views\Home\Index.aspx
Anda dapat melihat tampilan yang dimodifikasi dengan melihat aplikasi Visual Studio yang menyertai tutorial ini. Misalnya, Gambar 8 mengilustrasikan tampilan Indeks Kontak.
Gambar 08: Tampilan Indeks Kontak (Klik untuk melihat gambar ukuran penuh)
Ringkasan
Dalam perulangan ini, kami menambahkan fungsionalitas baru ke aplikasi Contact Manager kami dengan mengikuti metodologi desain aplikasi pengembangan berbasis pengujian. Kami mulai dengan membuat sekumpulan cerita pengguna. Kami membuat serangkaian pengujian unit yang sesuai dengan persyaratan yang dinyatakan oleh cerita pengguna. Akhirnya, kami menulis kode yang cukup untuk memenuhi persyaratan yang dinyatakan oleh pengujian unit.
Setelah selesai menulis kode yang cukup untuk memenuhi persyaratan yang dinyatakan oleh pengujian unit, kami memperbarui database dan tampilan kami. Kami menambahkan tabel Grup baru ke database kami dan memperbarui Model Data Kerangka Kerja Entitas kami. Kami juga membuat dan memodifikasi sekumpulan tampilan.
Dalam iterasi berikutnya -- iterasi akhir -- kami menulis ulang aplikasi kami untuk memanfaatkan Ajax. Dengan memanfaatkan Ajax, kami akan meningkatkan responsivitas dan performa aplikasi Contact Manager.