MVVM - การทดสอบหน่วย
แนวคิดเบื้องหลังการทดสอบหน่วยคือการใช้โค้ด (หน่วย) แบบแยกส่วนและเขียนวิธีการทดสอบที่ใช้โค้ดในลักษณะที่คาดหวังจากนั้นทดสอบเพื่อดูว่าได้ผลลัพธ์ตามที่คาดหวังหรือไม่
การทดสอบหน่วยจะถูกรวบรวมเช่นเดียวกับส่วนอื่น ๆ ของโครงการ
นอกจากนี้ยังดำเนินการโดยซอฟต์แวร์ทดสอบซึ่งสามารถเร่งความเร็วในการทดสอบแต่ละครั้งได้อย่างมีประสิทธิภาพยกนิ้วโป้งขึ้นหรือยกนิ้วลงเพื่อระบุว่าการทดสอบผ่านหรือล้มเหลวตามลำดับ
ลองมาดูตัวอย่างที่สร้างขึ้นก่อนหน้านี้ ต่อไปนี้คือการนำ Student Model ไปใช้
using System.ComponentModel;
namespace MVVMDemo.Model {
public class StudentModel {}
public class Student : INotifyPropertyChanged {
private string firstName;
private string lastName;
public string FirstName {
get { return firstName; }
set {
if (firstName != value) {
firstName = value;
RaisePropertyChanged("FirstName");
RaisePropertyChanged("FullName");
}
}
}
public string LastName {
get { return lastName; }
set {
if (lastName != value) {
lastName = value;
RaisePropertyChanged("LastName");
RaisePropertyChanged("FullName");
}
}
}
public string FullName {
get {
return firstName + " " + lastName;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
ต่อไปนี้คือการใช้งาน StudentView
<UserControl x:Class="MVVMDemo.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMDemo.Views"
xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel"
xmlns:data = "clr-namespace:MVVMDemo.Model"
xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"
mc:Ignorable = "d"
d:DesignHeight = "300" d:DesignWidth = "300">
<UserControl.Resources>
<DataTemplate DataType = "{x:Type data:Student}">
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>
<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<StackPanel Orientation = "Horizontal">
<ListBox ItemsSource = "{Binding Students}"
SelectedItem = "{Binding SelectedStudent}"/>
<Button Content = "Delete"
Command = "{Binding DeleteCommand}"
HorizontalAlignment = "Left"
VerticalAlignment = "Top"
Width = "75" />
</StackPanel>
</Grid>
</UserControl>
ต่อไปนี้คือการใช้งาน StudentViewModel
using MVVMDemo.Model;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System;
namespace MVVMDemo.ViewModel {
public class StudentViewModel {
public MyICommand DeleteCommand { get; set;}
public StudentViewModel() {
LoadStudents();
DeleteCommand = new MyICommand(OnDelete, CanDelete);
}
public ObservableCollection<Student> Students {
get;
set;
}
public void LoadStudents() {
ObservableCollection<Student> students = new ObservableCollection<Student>();
students.Add(new Student { FirstName = "Mark", LastName = "Allain" });
students.Add(new Student { FirstName = "Allen", LastName = "Brown" });
students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" });
Students = students;
}
private Student _selectedStudent;
public Student SelectedStudent {
get {
return _selectedStudent;
}
set {
_selectedStudent = value;
DeleteCommand.RaiseCanExecuteChanged();
}
}
private void OnDelete() {
Students.Remove(SelectedStudent);
}
private bool CanDelete() {
return SelectedStudent != null;
}
public int GetStudentCount() {
return Students.Count;
}
}
}
ต่อไปนี้คือไฟล์ MainWindow.xaml
<Window x:Class = "MVVMDemo.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local = "clr-namespace:MVVMDemo"
xmlns:views = "clr-namespace:MVVMDemo.Views"
mc:Ignorable = "d"
Title = "MainWindow" Height = "350" Width = "525">
<Grid>
<views:StudentView x:Name = "StudentViewControl"/>
</Grid>
</Window>
ต่อไปนี้คือการใช้งาน MyICommand ซึ่งใช้อินเทอร์เฟซ ICommand
using System;
using System.Windows.Input;
namespace MVVMDemo {
public class MyICommand : ICommand {
Action _TargetExecuteMethod;
Func<bool> _TargetCanExecuteMethod;
public MyICommand(Action executeMethod) {
_TargetExecuteMethod = executeMethod;
}
public MyICommand(Action executeMethod, Func<bool> canExecuteMethod) {
_TargetExecuteMethod = executeMethod;
_TargetCanExecuteMethod = canExecuteMethod;
}
public void RaiseCanExecuteChanged() {
CanExecuteChanged(this, EventArgs.Empty);
}
bool ICommand.CanExecute(object parameter) {
if (_TargetCanExecuteMethod != null) {
return _TargetCanExecuteMethod();
}
if (_TargetExecuteMethod != null) {
return true;
}
return false;
}
// Beware - should use weak references if command instance lifetime
is longer than lifetime of UI objects that get hooked up to command
// Prism commands solve this in their implementation
public event EventHandler CanExecuteChanged = delegate { };
void ICommand.Execute(object parameter) {
if (_TargetExecuteMethod != null) {
_TargetExecuteMethod();
}
}
}
}
เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะเห็นผลลัพธ์ต่อไปนี้ในหน้าต่างหลักของคุณ
ในการเขียนการทดสอบหน่วยสำหรับตัวอย่างข้างต้นให้เพิ่มโครงการทดสอบใหม่ลงในโซลูชัน
เพิ่มการอ้างอิงไปยังโครงการโดยคลิกขวาที่การอ้างอิง
เลือกโครงการที่มีอยู่แล้วคลิกตกลง
ตอนนี้ให้เราเพิ่มแบบทดสอบง่ายๆซึ่งจะตรวจสอบจำนวนนักเรียนตามที่แสดงในรหัสต่อไปนี้
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MVVMDemo.ViewModel;
namespace MVVMTest {
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
StudentViewModel sViewModel = new StudentViewModel();
int count = sViewModel.GetStudentCount();
Assert.IsTrue(count == 3);
}
}
}
ในการดำเนินการทดสอบนี้ให้เลือกทดสอบ→เรียกใช้→ตัวเลือกเมนูการทดสอบทั้งหมด
คุณสามารถเห็นใน Test Explorer ว่าการทดสอบผ่านแล้วเนื่องจากใน StudentViewModel มีการเพิ่มนักเรียนสามคน เปลี่ยนเงื่อนไขการนับจาก 3 เป็น 4 ดังแสดงในรหัสต่อไปนี้
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MVVMDemo.ViewModel;
namespace MVVMTest {
[TestClass]
public class UnitTest1 {
[TestMethod] public void TestMethod1() {
StudentViewModel sViewModel = new StudentViewModel();
int count = sViewModel.GetStudentCount();
Assert.IsTrue(count == 4);
}
}
}
เมื่อแผนการทดสอบถูกดำเนินการอีกครั้งคุณจะเห็นว่าการทดสอบล้มเหลวเนื่องจากจำนวนนักเรียนไม่เท่ากับ 4
เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นด้วยวิธีการทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น