6. Yineleme – Test odaklı geliştirme kullanma (VB)
Microsoft tarafından
Bu altıncı yinelemede, önce birim testleri yazıp birim testlerine kod yazarak uygulamamıza yeni işlevler ekleyeceğiz. Bu yinelemede kişi grupları ekleyeceğiz.
MVC Uygulaması ASP.NET Kişi Yönetimi Oluşturma (VB)
Bu öğretici serisinde, baştan sona bir Kişi Yönetimi uygulamasının tamamını oluşturuyoruz. Contact Manager uygulaması kişi listesi için kişi bilgilerini (adlar, telefon numaraları ve e-posta adresleri) depolamanıza olanak tanır.
Uygulamayı birden çok yineleme üzerinden derleyeceğiz. Her yinelemede uygulamayı aşamalı olarak iyileştiriyoruz. Bu çoklu yineleme yaklaşımının amacı, her değişikliğin nedenini anlamanıza olanak tanımaktır.
Yineleme #1 - Uygulamayı oluşturun. İlk yinelemede, Contact Manager'ı mümkün olan en basit şekilde oluştururuz. Temel veritabanı işlemleri için destek ekliyoruz: Oluşturma, Okuma, Güncelleştirme ve Silme (CRUD).
Yineleme #2 - Uygulamanın güzel görünmesini sağlayın. Bu yinelemede, MVC görünümü ana sayfasını ve basamaklı stil sayfasını varsayılan ASP.NET değiştirerek uygulamanın görünümünü iyileştireceğiz.
3. Yineleme - Form doğrulaması ekleyin. Üçüncü yinelemede temel form doğrulamasını ekleyeceğiz. Gerekli form alanlarını tamamlamadan kişilerin form göndermesini engelleriz. Ayrıca e-posta adreslerini ve telefon numaralarını doğrularız.
Yineleme #4 - Uygulamayı gevşek bir şekilde birleştirin. Bu dördüncü yinelemede, Contact Manager uygulamasının bakımını ve değiştirilmesini kolaylaştırmak için çeşitli yazılım tasarım desenlerinden yararlanıyoruz. Örneğin, uygulamamızı Depo desenini ve Bağımlılık Ekleme düzenini kullanacak şekilde yeniden düzenleyeceğiz.
Yineleme #5 - Birim testleri oluşturun. Beşinci yinelemede, birim testleri ekleyerek uygulamamızın bakımını ve değiştirilmesini kolaylaştırıyoruz. Veri modeli sınıflarımızla dalga geçiyoruz ve denetleyicilerimiz ve doğrulama mantığımız için birim testleri oluşturuyoruz.
Yineleme #6 - Test temelli geliştirmeyi kullanın. Bu altıncı yinelemede, önce birim testleri yazıp birim testlerine kod yazarak uygulamamıza yeni işlevler ekleyeceğiz. Bu yinelemede kişi grupları ekleyeceğiz.
Yineleme #7 - Ajax işlevselliğini ekleyin. Yedinci yinelemede Ajax için destek ekleyerek uygulamamızın yanıt hızını ve performansını iyileştiriyoruz.
Bu Yineleme
Contact Manager uygulamasının önceki yinelemesinde, kodumuz için bir güvenlik ağı sağlamak üzere birim testleri oluşturduk. Birim testlerini oluşturmanın amacı, kodumuzu değiştirmek için daha dayanıklı hale getirmekti. Birim testleri gerçekleştirdiğimizde kodumuzda herhangi bir değişiklik yapabilir ve mevcut işlevselliği bozup bozmadığımıza hemen karar verebiliriz.
Bu yinelemede, birim testlerini tamamen farklı bir amaç için kullanırız. Bu yinelemede, test temelli geliştirme adı verilen uygulama tasarım felsefesinin bir parçası olarak birim testlerini kullanırız. Test temelli geliştirme alıştırması yaptığınızda, önce testleri yazar ve ardından testlere karşı kod yazarsınız.
Daha kesin olarak, test temelli geliştirmeyi uygularken kod oluştururken tamamlamanız gereken üç adım vardır (Kırmızı/ Yeşil/Yeniden Düzenleme):
- Başarısız olan birim testi yazma (Kırmızı)
- Birim testini geçen kod yazma (Yeşil)
- Kodunuzu yeniden düzenleme (Yeniden düzenleme)
İlk olarak birim testini yazarsınız. Birim testi, kodunuzun nasıl davranmasını beklediğinizi ifade etmelidir. Birim testini ilk oluşturduğunuzda birim testi başarısız olmalıdır. Testi karşılayan herhangi bir uygulama kodu yazmadığınız için test başarısız olmalıdır.
Ardından, birim testinin geçmesi için yeterli kodu yazacaksınız. Amaç kodu mümkün olan en tembel, en eğimli ve en hızlı şekilde yazmaktır. Uygulamanızın mimarisini düşünmekle zaman kaybetmemelisiniz. Bunun yerine, birim testi tarafından ifade edilen amacı karşılamak için gereken en az miktarda kodu yazmaya odaklanmanız gerekir.
Son olarak, yeterli kodu yazdıktan sonra geri adım atabilir ve uygulamanızın genel mimarisini göz önünde bulundurabilirsiniz. Bu adımda, kodunuzun daha sürdürülebilir olması için, depo düzeni gibi yazılım tasarım desenlerinden yararlanarak kodunuzu yeniden yazar (yeniden düzenlersiniz). Kodunuz birim testlerinin kapsamına eklendiğinden, bu adımda kodunuzu korkusuzca yeniden yazabilirsiniz.
Test temelli geliştirmenin sonucunda elde edilen birçok avantaj vardır. İlk olarak, test temelli geliştirme sizi gerçekten yazılması gereken koda odaklanmaya zorlar. Sürekli olarak belirli bir testi geçmek için yeterli kodu yazmaya odaklandığınızdan, hiçbir zaman kullanmayacağınız çok miktarda kod yazmanız ve bu tür işlemlerin içine girmeniz engellenir.
İkincisi, "önce test et" tasarım metodolojisi, kodunuzun nasıl kullanılacağı açısından kod yazmaya zorlar. Başka bir deyişle, test temelli geliştirme yaparken, testlerinizi sürekli olarak kullanıcı perspektifinden yazarsınız. Bu nedenle test temelli geliştirme, daha temiz ve daha anlaşılır API'lere neden olabilir.
Son olarak, test temelli geliştirme sizi bir uygulama yazma işleminin normal bir parçası olarak birim testleri yazmaya zorlar. Proje son tarihi yaklaştıkça, test genellikle pencereden çıkan ilk şeydir. Öte yandan, test temelli geliştirme yaparken birim testleri yazma konusunda daha verimli olma olasılığınız daha yüksektir çünkü test temelli geliştirme, birim testlerini uygulama oluşturma sürecinin merkezi haline getirir.
Not
Test temelli geliştirme hakkında daha fazla bilgi edinmek için Michael Feathers'un Eski Kod ile Etkili Çalışma kitabını okumanızı öneririm.
Bu yinelemede, Contact Manager uygulamamıza yeni bir özellik ekleyeceğiz. Kişi Grupları için destek ekliyoruz. Kişilerinizi İş ve Arkadaş grupları gibi kategoriler halinde düzenlemek için Kişi Gruplarını kullanabilirsiniz.
Test temelli geliştirme sürecini izleyerek bu yeni işlevi uygulamamıza ekleyeceğiz. Önce birim testlerimizi yazacağız ve tüm kodumuzu bu testlere karşı yazacağız.
Test Edilenler
Önceki yinelemede ele aldığımız gibi, genellikle veri erişim mantığı için birim testleri yazmaz veya mantığı görüntülemezsiniz. Veritabanına erişim nispeten yavaş bir işlem olduğundan, veri erişim mantığı için birim testleri yazmazsınız. Görünüme erişmek görece yavaş bir işlem olan bir web sunucusu oluşturmayı gerektirdiği için görüntüleme mantığı için birim testleri yazmazsınız. Test çok hızlı bir şekilde tekrar tekrar yürütülemedikçe birim testi yazmamalısınız
Test temelli geliştirme birim testlerine göre oluşturulduğundan, başlangıçta denetleyici ve iş mantığı yazmaya odaklanıyoruz. Veritabanına veya görünümlere dokunmaktan kaçınıyoruz. Bu öğreticinin sonuna kadar veritabanını değiştirmeyeceğiz veya görünümlerimizi oluşturmayacağız. Test edilebileceklerle başlıyoruz.
Kullanıcı Hikayeleri Oluşturma
Test temelli geliştirme alıştırması yaparken, her zaman bir test yazarak başlarsınız. Bu soru hemen şu soruyu doğurur: İlk olarak hangi testi yazabileceğinize nasıl karar verirsiniz? Bu soruyu yanıtlamak için bir dizi kullanıcı hikayesi yazmanız gerekir.
Kullanıcı hikayesi, yazılım gereksiniminin çok kısa (genellikle bir cümle) açıklamasıdır. Kullanıcı açısından yazılmış bir gereksinimin teknik olmayan bir açıklaması olmalıdır.
Yeni Kişi Grubu işlevselliğinin gerektirdiği özellikleri açıklayan kullanıcı hikayeleri kümesi aşağıdadır:
- Kullanıcı kişi gruplarının listesini görüntüleyebilir.
- Kullanıcı yeni bir kişi grubu oluşturabilir.
- Kullanıcı mevcut bir kişi grubunu silebilir.
- Kullanıcı, yeni kişi oluştururken kişi grubunu seçebilir.
- Kullanıcı, mevcut bir kişiyi düzenlerken kişi grubunu seçebilir.
- Kişi gruplarının listesi Dizin görünümünde görüntülenir.
- Kullanıcı bir kişi grubuna tıkladığında, eşleşen kişilerin listesi görüntülenir.
Bu kullanıcı hikayeleri listesinin müşteri tarafından tamamen anlaşılabilir olduğuna dikkat edin. Teknik uygulama ayrıntılarından bahsedilmemiştir.
Uygulamanızı oluşturma sürecindeyken, kullanıcı hikayeleri kümesi daha iyi hale gelebilir. Bir kullanıcı hikayesini birden çok hikayeye (gereksinimler) bölebilirsiniz. Örneğin, yeni kişi grubu oluşturma işleminin doğrulamayı içermesi gerektiğine karar vekleyebilirsiniz. Kişi grubunu ad olmadan göndermek doğrulama hatası döndürmelidir.
Kullanıcı hikayelerinin listesini oluşturduktan sonra, ilk birim testinizi yazmaya hazırsınız. Kişi gruplarının listesini görüntülemek için bir birim testi oluşturarak başlayacağız.
Kişi Gruplarını Listeleme
İlk kullanıcı hikayemiz, bir kullanıcının kişi gruplarının listesini görüntüleyebilmesi gerektiğidir. Bu hikayeyi bir testle ifade etmeliyiz.
ContactManager.Tests projesinde Denetleyiciler klasörüne sağ tıklayıp Ekle, Yeni Test'i ve Birim Testi şablonunu seçerek yeni bir birim testi oluşturun (bkz. Şekil 1). Yeni birim testini GroupControllerTest.vb olarak adlandırın ve Tamam düğmesine tıklayın.
Şekil 01: GroupControllerTest birim testi ekleme (Tam boyutlu görüntüyü görüntülemek için tıklayın)
İlk birim testimiz Liste 1'de yer alır. Bu test, Grup denetleyicisinin Index() yönteminin bir Grup kümesi döndürdüğünü doğrular. Test, bir Grup koleksiyonunun görünüm verilerinde döndürüldüğünü doğrular.
Listeleme 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
Visual Studio'da Listeleme 1'e kodu ilk kez yazdığınızda, çok fazla kırmızı dalgalı çizgi alırsınız. GroupController veya Group sınıflarını oluşturmadık.
Bu noktada, ilk birim testimizi yürütemememiz için uygulamamızı bile oluşturamıyoruz. Bu iyi oldu. Bu, başarısız bir test olarak sayılır. Bu nedenle artık uygulama kodu yazmaya başlama iznimiz var. Testimizi yürütmek için yeterli kod yazmamız gerekiyor.
Listeleme 2'deki Grup denetleyicisi sınıfı, birim testini geçirmek için gereken en düşük kodu içerir. Index() eylemi, statik olarak kodlanmış bir Grup listesi döndürür (Grup sınıfı Listeleme 3'te tanımlanır).
Listeleme 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
Listeleme 3 - Models\Group.vb
Public Class Group
End Class
GroupController ve Group sınıflarını projemize ekledikten sonra ilk birim testimiz başarıyla tamamlanır (bkz. Şekil 2). Testi geçmek için gereken minimum çalışmayı yaptık. Kutlama zamanı.
Şekil 02: Başarı! (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Kişi Grupları Oluşturma
Artık ikinci kullanıcı hikayesine geçebiliriz. Yeni kişi grupları oluşturabilmemiz gerekiyor. Bu amacı bir testle ifade etmeliyiz.
Listeleme 4'teki test, Create() yöntemini yeni bir Grupla çağırmanın Grubu Index() yöntemi tarafından döndürülen Gruplar listesine eklediğini doğrular. Başka bir deyişle, yeni bir grup oluşturursam, yeni Grubu Index() yöntemi tarafından döndürülen Gruplar listesinden geri alabilmeliyim.
Listeleme 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
Listeleme 4'teki test, yeni bir kişi Grubu ile Grup denetleyicisi Create() yöntemini çağırır. Daha sonra test, Grup denetleyicisi Index() yöntemini çağırmanın verileri görüntülemede yeni Grubu döndürdüğünü doğrular.
Liste 5'teki değiştirilen Grup denetleyicisi, yeni testi geçmek için gereken en az değişikliği içerir.
Listeleme 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
Liste 5'teki Grup denetleyicisinin yeni bir Create() eylemi var. Bu eylem, Gruplar koleksiyonuna bir Grup ekler. Index() eyleminin, Gruplar koleksiyonunun içeriğini döndürecek şekilde değiştirildiğine dikkat edin.
Bir kez daha birim testini geçmek için gereken minimum çalışma miktarını gerçekleştirdik. Grup denetleyicisinde bu değişiklikleri yaptıktan sonra tüm birim testlerimiz geçer.
Doğrulama Ekleme
Bu gereksinim, kullanıcı hikayesinde açıkça belirtilmedi. Ancak, bir Grubun bir ada sahip olmasını zorunlu kılabilir. Aksi takdirde, kişileri Gruplar halinde düzenlemek çok yararlı olmaz.
6. liste, bu amacı ifade eden yeni bir test içerir. Bu test, bir ad sağlamadan Grup oluşturma girişiminin model durumunda doğrulama hata iletisiyle sonuçlandığını doğrular.
Listeleme 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
Bu testi karşılamak için Grup sınıfımıza bir Ad özelliği eklememiz gerekir (bkz. Listeleme 7). Ayrıca, Grup denetleyicisinin Create() eylemine küçük bir doğrulama mantığı eklememiz gerekir (bkz. Listeleme 8).
Listeleme 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
Liste 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
Grup denetleyicisi Create() eyleminin artık hem doğrulama hem de veritabanı mantığı içerdiğine dikkat edin. Şu anda, Grup denetleyicisi tarafından kullanılan veritabanı bellek içi bir koleksiyondan başka bir şeyden ibarettir.
Yeniden Düzenleme Zamanı
Kırmızı/Yeşil/Yeniden Düzenleme'nin üçüncü adımı Yeniden Düzenleme bölümüdür. Bu noktada kodumuzdan geri dönmemiz ve tasarımını geliştirmek için uygulamamızı nasıl yeniden düzenleyebileceğimizi düşünmemiz gerekir. Yeniden düzenleme aşaması, yazılım tasarım ilkelerini ve desenlerini uygulamanın en iyi yolu hakkında çok düşündüğümüz aşamadır.
Kodun tasarımını geliştirmek için seçtiğimiz herhangi bir şekilde kodumuzu değiştirebiliriz. Mevcut işlevselliği bozmamızı engelleyen birim testlerinden oluşan bir güvenlik ağımız var.
Şu anda, Grup denetleyicimiz iyi bir yazılım tasarımı açısından bir karmaşa. Grup denetleyicisi, karmaşık bir doğrulama ve veri erişim kodu karmaşası içerir. Tek Sorumluluk İlkesi'ni ihlal etmekten kaçınmak için bu endişeleri farklı sınıflara ayırmamız gerekir.
Yeniden düzenlenmiş Grup denetleyicisi sınıfımız Listeleme 9'da yer alır. Denetleyici ContactManager hizmet katmanını kullanacak şekilde değiştirildi. Bu, Kişi denetleyicisinde kullandığımız hizmet katmanıyla aynıdır.
Liste 10, grupları doğrulamayı, listelemeyi ve oluşturmayı desteklemek için ContactManager hizmet katmanına eklenen yeni yöntemleri içerir. IContactManagerService arabirimi yeni yöntemleri içerecek şekilde güncelleştirildi.
Liste 11, IContactManagerRepository arabirimini uygulayan yeni bir FakeContactManagerRepository sınıfı içerir. IContactManagerRepository arabirimini de uygulayan EntityContactManagerRepository sınıfından farklı olarak, yeni FakeContactManagerRepository sınıfımız veritabanıyla iletişim kurmaz. FakeContactManagerRepository sınıfı, veritabanı için ara sunucu olarak bellek içi koleksiyonu kullanır. Bu sınıfı birim testlerimizde sahte depo katmanı olarak kullanacağız.
Listeleme 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
Liste 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
Listeleme 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
IContactManagerRepository arabirimini değiştirmek için EntityContactManagerRepository sınıfında CreateGroup() ve ListGroups() yöntemlerini uygulamak için kullanılması gerekir. Bunu yapmak için en tembel ve en hızlı yol aşağıdakine benzer saplama yöntemleri eklemektir:
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
Son olarak, uygulamamızın tasarımında yapılan bu değişiklikler, birim testlerimizde bazı değişiklikler yapmamızı gerektirir. Şimdi birim testlerini gerçekleştirirken FakeContactManagerRepository'yi kullanmamız gerekiyor. Güncelleştirilmiş GroupControllerTest sınıfı Listeleme 12'de yer alır.
Listeleme 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
Tüm bu değişiklikleri yaptıktan sonra, bir kez daha tüm birim testlerimiz geçer. Kırmızı/Yeşil/Yeniden Düzenleme döngüsünün tamamını tamamladık. İlk iki kullanıcı hikayesini uyguladık. Artık kullanıcı hikayelerinde ifade edilen gereksinimler için destekleyici birim testlerimiz var. Kullanıcı hikayelerinin geri kalanını uygulamak için aynı Kırmızı/Yeşil/Yeniden Düzenleme döngüsünün yinelenmesi gerekir.
Veritabanımızı Değiştirme
Ne yazık ki, birim testlerimiz tarafından ifade edilen tüm gereksinimleri karşılamış olsak da, işimiz yapılmamaktadır. Yine de veritabanımızı değiştirmemiz gerekiyor.
Yeni bir Grup veritabanı tablosu oluşturmamız gerekiyor. Şu adımları izleyin:
- Sunucu Gezgini penceresinde Tablolar klasörüne sağ tıklayın ve Yeni Tablo Ekle menü seçeneğini belirleyin.
- Tablo Tasarım Aracı aşağıda açıklanan iki sütunu girin.
- Kimlik sütununu birincil anahtar ve Kimlik sütunu olarak işaretleyin.
- Disketin simgesine tıklayarak yeni tabloyu Gruplar adıyla kaydedin.
Sütun Adı | Veri Türü | Null'lara İzin Ver |
---|---|---|
Id | int | Yanlış |
Name | nvarchar(50) | Yanlış |
Ardından, Kişiler tablosundaki tüm verileri silmemiz gerekir (aksi takdirde, Kişiler ve Gruplar tabloları arasında ilişki oluşturamayız). Şu adımları izleyin:
- Kişiler tablosuna sağ tıklayın ve Tablo Verilerini Göster menü seçeneğini belirleyin.
- Tüm satırları silin.
Ardından, Gruplar veritabanı tablosu ile mevcut Kişiler veritabanı tablosu arasında bir ilişki tanımlamamız gerekir. Şu adımları izleyin:
- Sunucu Gezgini penceresinde Kişiler tablosuna çift tıklayarak Tablo Tasarım Aracı açın.
- Kişiler tablosuna GroupId adlı yeni bir tamsayı sütunu ekleyin.
- Yabancı Anahtar İlişkileri iletişim kutusunu açmak için İlişki düğmesine tıklayın (bkz. Şekil 3).
- Ekle düğmesine tıklayın.
- Tablo ve Sütun Belirtimi düğmesinin yanında görünen üç nokta düğmesine tıklayın.
- Tablolar ve Sütunlar iletişim kutusunda birincil anahtar tablosu olarak Gruplar'ı ve birincil anahtar sütunu olarak Kimlik'i seçin. Yabancı anahtar tablosu olarak Kişiler'i ve yabancı anahtar sütunu olarak GroupId'yi seçin (bkz. Şekil 4). Tamam düğmesine tıklayın.
- INSERT ve UPDATE Belirtimi'nin altında, Kuralı Sil için Art Arda Ekle değerini seçin.
- Yabancı Anahtar İlişkileri iletişim kutusunu kapatmak için Kapat düğmesine tıklayın.
- Kişiler tablosundaki değişiklikleri kaydetmek için Kaydet düğmesine tıklayın.
Şekil 03: Veritabanı tablosu ilişkisi oluşturma (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Şekil 04: Tablo ilişkilerini belirtme (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Veri Modelimizi Güncelleştirme
Ardından, yeni veritabanı tablosunu temsil etmek için veri modelimizi güncelleştirmemiz gerekiyor. Şu adımları izleyin:
- Entity Tasarım Aracı açmak için Models klasöründeki ContactManagerModel.edmx dosyasına çift tıklayın.
- Tasarım Aracı yüzeye sağ tıklayın ve Modeli Veritabanından Güncelleştir menü seçeneğini belirleyin.
- Güncelleştirme Sihirbazı'nda Gruplar tablosunu seçin ve Son düğmesine tıklayın (bkz. Şekil 5).
- Gruplar varlığına sağ tıklayın ve Yeniden Adlandır menü seçeneğini belirleyin. Gruplar varlığının adını Grup (tekil) olarak değiştirin.
- Kişi varlığının en altında görüntülenen Gruplar gezinti özelliğine sağ tıklayın. Gruplar gezinti özelliğinin adını Grup (tekil) olarak değiştirin.
Şekil 05: Veritabanından bir Entity Framework modelini güncelleştirme (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Bu adımları tamamladıktan sonra veri modeliniz hem Kişiler hem de Gruplar tablolarını temsil eder. Varlık Tasarım Aracı her iki varlığı da göstermelidir (bkz. Şekil 6).
Şekil 06: Grup ve Kişi'yi görüntüleyen varlık Tasarım Aracı(Tam boyutlu görüntüyü görüntülemek için tıklayın)
Depo Sınıflarımızı Oluşturma
Ardından, depo sınıfımızı uygulamamız gerekir. Bu yineleme sırasında, birim testlerimizi karşılamak için kod yazarken IContactManagerRepository arabirimine birkaç yeni yöntem ekledik. IContactManagerRepository arabiriminin son sürümü Listeleme 14'te yer alır.
Listeleme 14 - Models\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
Gerçek EntityContactManagerRepository sınıfımızda kişi gruplarıyla çalışmayla ilgili yöntemlerin hiçbirini uygulamadık. Şu anda EntityContactManagerRepository sınıfı, IContactManagerRepository arabiriminde listelenen kişi grubu yöntemlerinin her biri için saptama yöntemlerine sahiptir. Örneğin, ListGroups() yöntemi şu anda şöyle görünür:
Public Function ListGroups() As IEnumerable(Of Group) Implements IContactManagerRepository.ListGroups
throw New NotImplementedException()
End Function
Saptama yöntemleri, uygulamamızı derlememizi ve birim testlerini geçirmemizi sağladı. Ancak şimdi bu yöntemleri uygulama zamanı geldi. EntityContactManagerRepository sınıfının son sürümü Listeleme 13'te yer alır.
Listeleme 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
Görünümleri Oluşturma
Varsayılan ASP.NET görünüm altyapısını kullandığınızda MVC uygulamasını ASP.NET. Bu nedenle, belirli bir birim testine yanıt olarak görünümler oluşturmazsınız. Ancak, bir uygulama görünümler olmadan işe yaramaz olacağından, Contact Manager uygulamasındaki görünümleri oluşturmadan ve değiştirmeden bu yinelemeyi tamamlayamayız.
Kişi gruplarını yönetmek için aşağıdaki yeni görünümleri oluşturmamız gerekiyor (bkz. Şekil 7):
- Views\Group\Index.aspx - Kişi gruplarının listesini görüntüler
- Views\Group\Delete.aspx - Kişi grubunu silmek için onay formunu görüntüler
Şekil 07: Grup Dizini görünümü (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Aşağıdaki mevcut görünümleri kişi gruplarını içerecek şekilde değiştirmemiz gerekir:
- Views\Home\Create.aspx
- Views\Home\Edit.aspx
- Views\Home\Index.aspx
Bu öğreticiye eşlik eden Visual Studio uygulamasına bakarak değiştirilmiş görünümleri görebilirsiniz. Örneğin, Şekil 8'de Kişi Dizini görünümü gösterilmektedir.
Şekil 08: Kişi Dizini görünümü (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Özet
Bu yinelemede, test temelli geliştirme uygulaması tasarım metodolojisini izleyerek Contact Manager uygulamamıza yeni işlevler ekledik. İlk olarak bir kullanıcı hikayeleri kümesi oluşturduk. Kullanıcı hikayeleri tarafından ifade edilen gereksinimlere karşılık gelen bir dizi birim testi oluşturduk. Son olarak, birim testlerinin ifade ettiği gereksinimleri karşılamak için yeterli kodu yazdık.
Birim testlerinin ifade ettiği gereksinimleri karşılamak için yeterli kod yazmayı tamamladıktan sonra veritabanımızı ve görünümlerimizi güncelleştirdik. Veritabanımıza yeni bir Gruplar tablosu ekledik ve Entity Framework Veri Modelimizi güncelleştirdik. Ayrıca bir görünüm kümesi oluşturup değiştirdik.
Sonraki yinelemede (son yinelemede) Ajax'ın avantajlarından yararlanmak için uygulamamızı yeniden yazacağız. Ajax'ın avantajlarından yararlanarak Contact Manager uygulamasının yanıt hızını ve performansını geliştireceğiz.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin