Sviluppare unapp per WP7    in TDD? Si può fare!
Who am I?• Developer freelance:  – C# Asp.net Mvc, Wpf, Wp7  – Python Django  – Blog: orangecode.it/blog• WEBdeBS founder
What we’re going to see•   TDD•   MVVM•   Code..•   Code…•   …some more code!
The show case• Basic application• Download user songs list from  SoundCloud.com• Display the list• View song’s detail
Screen Shot
Let’s do it with code behind
Trackpublic class Track{  public int Id{get; set; }  public string Kind { get; set; }  public string Title { get; set; }  ...
Xaml<phone:PhoneApplicationPage >   <Grid x:Name="ContentPanel”>      <Grid.RowDefinitions>             <RowDefinition Hei...
Xaml <ItemsControl Grid.Row="1” x:Name="songsList">   <ItemsControl.ItemTemplate>       <DataTemplate>         <StackPanel...
Xaml<StackPanel Orientation="Horizontal"> <TextBox x:Name="searchedText" /> <Button Content="Search" Click="Search" /></St...
Xaml<ItemsControl x:Name="songsList">   <ItemsControl.ItemTemplate>    <DataTemplate>       <StackPanel Orientation="Horiz...
Code behind MainViewpublic partial class MainView :PhoneApplicationPage    {      public MainView()      {         Initial...
Code behind MainViewprivate void Search(object sender, EventArgs e){        RestClient client = new RestClient        {   ...
Code behind MainView client.ExecuteAsync<List<Track>>(request, response =>    {       songsList.ItemsSource = response.Dat...
Code behind MainViewprivate void ShowDetail(object sender, GestureEventArgs e){        NavigationService.Navigate(        ...
Xaml DetailView<phone:PhoneApplicationPage x:Class="OrangeCode.SoundCloud.View.MainView” >  <Grid x:Name="LayoutRoot" Back...
Xaml DetailView<Grid x:Name="ContentPanel”>   <StackPanel>       <Image x:Name="image” />       <TextBlock x:Name="creatio...
Code behind DetailViewpublic partial class DetailView : PhoneApplicationPage {    public DetailView()    {       Initializ...
Code behind DetailViewprotected override void OnNavigatedTo(NavigationEventArgs e){       string id = NavigationContext.Qu...
Code behind DetailView    client.ExecuteAsync<List<Track>>(request, response =>    {          image.Source = new BitmapIma...
Problem with code behind• Code coupled with UI  – Xaml + Code Behind -> one class• Not testable
MVVM approach• Architectural Pattern• Derived from Presentation Model pattern  (Fowler)• Clear separation between UI and L...
MVVM approach• Structure our code:  – ViewModel (c#): Logic  – View (Xaml): Presentation  – No more code behind• Now the V...
Test Driven Development• As easy as complex• Life Cycle:  – Write test (red)  – Write logic to pass the test (green)  – Re...
Test Driven Development• It’s about code design, not test• Test suite are good side effect of  tdd• It require a lot of di...
Testing Tools• Nunit for Windows Phone 7• No official mocking framework for  Windows Phone 7, but I found out  that Moq 3....
TDD• Download searched user songs list  from SoundCloud.com
TDD• There is a list of track that i’ve to  show
TDDnamespace OrangeCode.SoundCloudFixture{  public class MainViewModelFixture  {  }}namespace OrangeCode.SoundCloud{  publ...
TDD -RedWrite test:   [Test]   public void Constructor_Should_Initialize_TrackList()   {     MainViewModel viewModel = new...
TDDYou are not allowed to write anyproduction code unless it is to make afailing unit test pass.                    Uncle ...
TDD - Redpublic class MainViewModel{  public IList<Track> Tracks  {      get ;      set ;  }}
TDD
TDDYou are not allowed to write any moreproduction code than is sufficient topass the one failing unit test.              ...
TDD - Greenpublic class MainViewModel{  public IList<Track> Tracks { get; set; }    public MainViewModel()    {      Track...
TDD
TDD –Refactorpublic class MainViewModel{    private IList<Track> _tracks;    public IList<Track> Tracks    {      get { re...
TDD - Refactor
TDD• Download searched user songs list  from SoundCloud.com
Architecture   MainViewModel      Ilist<Track>SearchUserTrack(string      ) Search             Rest Call Service
Architecture                   public interface ISearchService    Main           { ViewModel           IList<Track> Search...
TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){   Mock<ISearchService> service = new Mock<ISearchService>...
TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){   Mock<ISearchService> service = new Mock<ISearchService>...
TDD - Mock• Simulated objects that mimic the behavior  of real objects in controlled ways• Mock objects have the same inte...
TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){   Mock<ISearchService> service = new Mock<ISearchService>...
TDD- ICommand• The ICommand interface enables the  abstraction of a parameterized method call  through its Execute method....
TDD- DelegateCommand• ICommand whose delegates can be  attached for Execute(T)• Execute(T) is the method to be  called whe...
TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){   Mock<ISearchService> service = new Mock<ISearchService>...
TDD - RedAdd properties in order to compilepublic string SearchedText { get; set; }public DelegateCommand Search { get; se...
TDD - Red
TDD - Greenpublic string SearchedText { get; set; }public DelegateCommand Search { get; set; }public MainViewModel(ISearch...
TDD - Green
TDD - Refactorpublic string SearchedText { get; set; }public DelegateCommand Search { get; private set; }public MainViewMo...
TDD - Refactor
TDD• Display the list
TDD[Test]public void Search_Should_UpdateTrackList(){  _searchService.Setup(p =>p.SearchUserTrack("michelecapra")).Returns...
TDD[Test]public void Search_Should_UpdateTrackList(){  _searchService.Setup(p =>p.SearchUserTrack("michelecapra")).Returns...
TDD[Test]public void Search_Should_UpdateTrackList(){  _searchService.Setup(p =>p.SearchUserTrack("michelecapra")).Returns...
TDD - Redpublic string SearchedText { get; set; }public DelegateCommand Search { get; private set; }public MainViewModel(I...
TDD - Red
TDD - Greenprivate void OnSearch(){  _tracks= _searchService.SearchUserTrack(SearchedText);}
TDD - Green
TDD• View song’s detail
TDD• We need to introduce the  NavigationService• But how to decouple it from our  ViewModel?
TDD – Navigation Servicepublic interface INavigationService                    THX to{  void NavigateTo(Uri pageUri);     ...
TDD [Test] public void ShowDetail_Should_NavigateToDetailView() {   var navigationService = new Mock<INavigationService>()...
TDD [Test] public void ShowDetail_Should_NavigateToDetailView() {   var navigationService = new Mock<INavigationService>()...
TDD [Test] public void ShowDetail_Should_NavigateToDetailView() {   var navigationService = new Mock<INavigationService>()...
TDD [Test] public void ShowDetail_Should_NavigateToDetailView() {   var navigationService = new Mock<INavigationService>()...
TDD - Redpublic class MainViewModel{  private IList<Track> _tracks;   public IList<Track> Tracks   {      get { return _tr...
TDD - Redpublic MainViewModel(ISearchService searchService,INavigationService navigationService) {    _searchService = sea...
TDD - Redpublic MainViewModel(ISearchService searchService,INavigationService navigationService) {    _searchService = sea...
TDD - Red
TDD - Greenprivate readonly INavigationService _navigationService;…public DelegateCommand<Track> ShowDetail{get; set; }… p...
TDD - Greenprivate void OnSearch(){  _tracks= _searchService.SearchUserTrack(SearchedText);}private void OnShowDetail(Trac...
TDD - Green
TDD - Refactorprivate readonly INavigationService _navigationService;public DelegateCommand<Track> ShowDetail{get; private...
TDD - Refactorprivate void OnSearch(){  _tracks= _searchService.SearchUserTrack(SearchedText);}private void OnShowDetail(T...
TDD - Refactor
TDD – Test suite refactor [Test] public void ShowDetail_Should_NavigateToDetailView() {   var navigationService = new Mock...
TDD – Test suite refactor [Test] public void ShowDetail_Should_NavigateToDetailView() {   var navigationService = new Mock...
TDD – Test suite refactorpublic class MainViewModelFixture{  private Mock<INavigationService> _navigationService;  private...
TDD – Test suite refactorpublic class MainViewModelFixture{  private Mock<INavigationService> _navigationService;  private...
ViewModel and UI• FrameworkElement.DataContext• “A directly embedded object that  serves as data context for any  bindings...
ViewModel and UIpublic partial class MainView :PhoneApplicationPage{     public MainView()     {        InitializeComponen...
MainView<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">   <Grid.RowDefinitions>        <RowDefinition Height=...
MainView<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">   <Grid.RowDefinitions>        <RowDefinition Height=...
MainView<ItemsControl Grid.Row="1" ItemsSource="{Binding Tracks}” >  <ItemsControl.ItemTemplate>     <DataTemplate>       ...
MainView<ItemsControl Grid.Row="1" ItemsSource="{Binding Tracks}” >  <ItemsControl.ItemTemplate>     <DataTemplate>       ...
INotifyPropertyChanged• INotifyPropertyChanged interface is  used to notify clients, typically  binding clients, that a pr...
INotifyPropertyChangedpublic class MainViewModel : INotifyPropertyChanged{  public event PropertyChangedEventHandler Prope...
INotifyPropertyChanged private void ExecuteSearch() {   _tracks=_service.SearchUserTrack(SearchedUser);   NotifyPropertyCh...
RecapWhat we have seen:-TDD (unit test, mock)-MVVM (commanding, binding,INotifyPropertyChanged, DataContext)
Node.JS
Be in contactMail: michele@orangecode.itTwitter: @piccoloaiutanteWeb: www.orangecode.itBlog: www.orangecode.it/blogGitHub:...
That’s all folks
Nächste SlideShare
Wird geladen in …5
×

Developing application for Windows Phone 7 in TDD

1.691 Aufrufe

Veröffentlicht am

A real example of how to develop an application for Windows Phone 7 with Test Driven Development approach. In this presentation you'll see also hoew to implements the Model-View-ViewModel (MVVM) pattern.

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Developing application for Windows Phone 7 in TDD

  1. 1. Sviluppare unapp per WP7 in TDD? Si può fare!
  2. 2. Who am I?• Developer freelance: – C# Asp.net Mvc, Wpf, Wp7 – Python Django – Blog: orangecode.it/blog• WEBdeBS founder
  3. 3. What we’re going to see• TDD• MVVM• Code..• Code…• …some more code!
  4. 4. The show case• Basic application• Download user songs list from SoundCloud.com• Display the list• View song’s detail
  5. 5. Screen Shot
  6. 6. Let’s do it with code behind
  7. 7. Trackpublic class Track{ public int Id{get; set; } public string Kind { get; set; } public string Title { get; set; } public string Description { get; set; } public string Artwork_url { get; set; } public string Created_at { get; set; }}
  8. 8. Xaml<phone:PhoneApplicationPage > <Grid x:Name="ContentPanel”> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <TextBox x:Name="searchedText" /> <Button Content="Search" Click="Search" /> </StackPanel>
  9. 9. Xaml <ItemsControl Grid.Row="1” x:Name="songsList"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Source="{Binding Image}" /> <TextBlock Text="{Binding Title}"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid></phone:PhoneApplicationPage>
  10. 10. Xaml<StackPanel Orientation="Horizontal"> <TextBox x:Name="searchedText" /> <Button Content="Search" Click="Search" /></StackPanel>
  11. 11. Xaml<ItemsControl x:Name="songsList"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Source="{Binding Image}”/> <TextBlock Text="{Binding Title}"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate></ItemsControl>
  12. 12. Code behind MainViewpublic partial class MainView :PhoneApplicationPage { public MainView() { InitializeComponent(); } private void Search(object sender, EventArgs e) { RestClient client = new RestClient { BaseUrl "http://api.soundcloud.com/users/"+searchedText.Text+"/tracks?client_id=eaf7649b0de68f902a4607c0b730e226" }; var request = new RestRequest { RequestFormat = DataFormat.Json }; client.ExecuteAsync<List<Track>>(request, response => { songsList.ItemsSource = response.Data; }); } private void ShowDetail(object sender, GestureEventArgs e) { NavigationService.Navigate(new Uri("/View/DetailView.xaml?id="+ ((Track)((StackPanel)sender).DataContext).Id, UriKind.Relative)); } }
  13. 13. Code behind MainViewprivate void Search(object sender, EventArgs e){ RestClient client = new RestClient { BaseUrl "http://api.soundcloud.com/ users/"+searchedText.Text+"/tracks? client_id=eaf7649b0de68f902a4607c0b730e226" }; var request = new RestRequest { RequestFormat = DataFormat.Json };
  14. 14. Code behind MainView client.ExecuteAsync<List<Track>>(request, response => { songsList.ItemsSource = response.Data; });}
  15. 15. Code behind MainViewprivate void ShowDetail(object sender, GestureEventArgs e){ NavigationService.Navigate( new Uri( "/View/DetailView.xaml?id="+ ((Track)((StackPanel)sender).DataContext).Id, UriKind.Relative ) );}
  16. 16. Xaml DetailView<phone:PhoneApplicationPage x:Class="OrangeCode.SoundCloud.View.MainView” > <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <Image x:Name="image" Width="200" Height="200” /> <TextBlock x:Name="creationDate" FontSize="22” /> <TextBlock x:Name="title" FontSize="28” /> <TextBlock x:Name="description” TextWrapping=Wrap/> </StackPanel> </Grid> </Grid></phone:PhoneApplicationPage>
  17. 17. Xaml DetailView<Grid x:Name="ContentPanel”> <StackPanel> <Image x:Name="image” /> <TextBlock x:Name="creationDate” /> <TextBlock x:Name="title” /> <TextBlock x:Name="description” /> </StackPanel></Grid>
  18. 18. Code behind DetailViewpublic partial class DetailView : PhoneApplicationPage { public DetailView() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { string id = NavigationContext.QueryString["id"]; RestClient client = new RestClient { BaseUrl = "http://api.soundcloud.com/tracks?client_id=eaf7649b0de68f902a4607c0b730e226&ids=" + id }; var request = new RestRequest { RequestFormat = DataFormat.Json }; client.ExecuteAsync<List<Track>>(request, response => { image.Source = new BitmapImage(new Uri(response.Data[0].Image)); creationDate.Text = response.Data[0].CreationDate; description.Text = response.Data[0].Description; title.Text = response.Data[0].Title; }); } }
  19. 19. Code behind DetailViewprotected override void OnNavigatedTo(NavigationEventArgs e){ string id = NavigationContext.QueryString["id"]; RestClient client = new RestClient { BaseUrl = "http://api.soundcloud.com/tracks? client_id=eaf7649b0de68f902a4607c0b730e226&ids=" + id }; var request = new RestRequest { RequestFormat = DataFormat.Json };
  20. 20. Code behind DetailView client.ExecuteAsync<List<Track>>(request, response => { image.Source = new BitmapImage( new Uri(response.Data[0].Image) ); creationDate.Text = response.Data[0].CreationDate; description.Text = response.Data[0].Description; title.Text = response.Data[0].Title; });}
  21. 21. Problem with code behind• Code coupled with UI – Xaml + Code Behind -> one class• Not testable
  22. 22. MVVM approach• Architectural Pattern• Derived from Presentation Model pattern (Fowler)• Clear separation between UI and Logic UI ViewModel Collections, DelegateCommand, Properties
  23. 23. MVVM approach• Structure our code: – ViewModel (c#): Logic – View (Xaml): Presentation – No more code behind• Now the ViewModel is testable
  24. 24. Test Driven Development• As easy as complex• Life Cycle: – Write test (red) – Write logic to pass the test (green) – Refactor code (refactor) – Again..
  25. 25. Test Driven Development• It’s about code design, not test• Test suite are good side effect of tdd• It require a lot of discipline and practice
  26. 26. Testing Tools• Nunit for Windows Phone 7• No official mocking framework for Windows Phone 7, but I found out that Moq 3.1 for silverlight works!
  27. 27. TDD• Download searched user songs list from SoundCloud.com
  28. 28. TDD• There is a list of track that i’ve to show
  29. 29. TDDnamespace OrangeCode.SoundCloudFixture{ public class MainViewModelFixture { }}namespace OrangeCode.SoundCloud{ public class MainViewModel { }}
  30. 30. TDD -RedWrite test: [Test] public void Constructor_Should_Initialize_TrackList() { MainViewModel viewModel = new MainViewModel(); Assert.IsNotNull(viewModel.Tracks); }
  31. 31. TDDYou are not allowed to write anyproduction code unless it is to make afailing unit test pass. Uncle Bob Martin
  32. 32. TDD - Redpublic class MainViewModel{ public IList<Track> Tracks { get ; set ; }}
  33. 33. TDD
  34. 34. TDDYou are not allowed to write any moreproduction code than is sufficient topass the one failing unit test. Uncle Bob Martin
  35. 35. TDD - Greenpublic class MainViewModel{ public IList<Track> Tracks { get; set; } public MainViewModel() { Tracks = new List<Track>(); }}
  36. 36. TDD
  37. 37. TDD –Refactorpublic class MainViewModel{ private IList<Track> _tracks; public IList<Track> Tracks { get { return _tracks; } } public MainViewModel() { _tracks = new List<Track>(); }}
  38. 38. TDD - Refactor
  39. 39. TDD• Download searched user songs list from SoundCloud.com
  40. 40. Architecture MainViewModel Ilist<Track>SearchUserTrack(string ) Search Rest Call Service
  41. 41. Architecture public interface ISearchService Main { ViewModel IList<Track> SearchUserTrack(string user); } public class SearchService : ISearchService {ISearchService public IList<Track> SearchUserTrack(string user){ } } Search Rest Call Service
  42. 42. TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){ Mock<ISearchService> service = new Mock<ISearchService>(); MainViewModel viewModel = new MainViewModel(service.Object); viewModel.SearchedText = "michelecapra"; viewModel.Search.Execute(); service.Verify(p=>p.SearchUserTrack("michelecapra"));}
  43. 43. TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){ Mock<ISearchService> service = new Mock<ISearchService>(); MainViewModel viewModel = new MainViewModel(service.Object); viewModel.SearchedText = "michelecapra"; viewModel.Search.Execute(); service.Verify(p=>p.SearchUserTrack("michelecapra"));}
  44. 44. TDD - Mock• Simulated objects that mimic the behavior of real objects in controlled ways• Mock objects have the same interface as the real objects they mimic, allowing a client object to remain unaware of whether it is using a real object or a mock object.
  45. 45. TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){ Mock<ISearchService> service = new Mock<ISearchService>(); MainViewModel viewModel = new MainViewModel(service.Object); viewModel.SearchedText = "michelecapra"; viewModel.Search.Execute(); service.Verify(p=>p.SearchUserTrack("michelecapra"));}
  46. 46. TDD- ICommand• The ICommand interface enables the abstraction of a parameterized method call through its Execute method.• Typically objects implement this interface to enable method calls on the objects through the use of XAML bindings.
  47. 47. TDD- DelegateCommand• ICommand whose delegates can be attached for Execute(T)• Execute(T) is the method to be called when the command is invoked.<Button Command=“”></Button>
  48. 48. TDD[Test]public void Search_Should_RetrieveSearchedUserTrack (){ Mock<ISearchService> service = new Mock<ISearchService>(); MainViewModel viewModel = new MainViewModel(service.Object); viewModel.SearchedText = "michelecapra"; viewModel.Search.Execute(); service.Verify(p=>p.SearchUserTrack("michelecapra"));}
  49. 49. TDD - RedAdd properties in order to compilepublic string SearchedText { get; set; }public DelegateCommand Search { get; set; }
  50. 50. TDD - Red
  51. 51. TDD - Greenpublic string SearchedText { get; set; }public DelegateCommand Search { get; set; }public MainViewModel(ISearchService searchService){ _searchService = searchService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch);}private void OnSearch(){ _searchService.SearchUserTrack(SearchedText);}
  52. 52. TDD - Green
  53. 53. TDD - Refactorpublic string SearchedText { get; set; }public DelegateCommand Search { get; private set; }public MainViewModel(ISearchService searchService){ _searchService = searchService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch);}private void OnSearch(){ _searchService.SearchUserTrack(SearchedText);}
  54. 54. TDD - Refactor
  55. 55. TDD• Display the list
  56. 56. TDD[Test]public void Search_Should_UpdateTrackList(){ _searchService.Setup(p =>p.SearchUserTrack("michelecapra")).Returns(new List<Track>{newTrack()}); _viewModel.SearchedText = "michelecapra"; _viewModel.Search.Execute(); Assert.AreEqual(_viewModel.Tracks.Count, 1);}
  57. 57. TDD[Test]public void Search_Should_UpdateTrackList(){ _searchService.Setup(p =>p.SearchUserTrack("michelecapra")).Returns(new List<Track>{newTrack()}); _viewModel.SearchedText = "michelecapra"; _viewModel.Search.Execute(); Assert.AreEqual(_viewModel.Tracks.Count, 1);}
  58. 58. TDD[Test]public void Search_Should_UpdateTrackList(){ _searchService.Setup(p =>p.SearchUserTrack("michelecapra")).Returns(new List<Track>{newTrack()}); _viewModel.SearchedText = "michelecapra"; _viewModel.Search.Execute(); Assert.AreEqual(_viewModel.Tracks.Count, 1);}
  59. 59. TDD - Redpublic string SearchedText { get; set; }public DelegateCommand Search { get; private set; }public MainViewModel(ISearchService searchService){ _searchService = searchService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch);}private void OnSearch(){ _searchService.SearchUserTrack(SearchedText);}
  60. 60. TDD - Red
  61. 61. TDD - Greenprivate void OnSearch(){ _tracks= _searchService.SearchUserTrack(SearchedText);}
  62. 62. TDD - Green
  63. 63. TDD• View song’s detail
  64. 64. TDD• We need to introduce the NavigationService• But how to decouple it from our ViewModel?
  65. 65. TDD – Navigation Servicepublic interface INavigationService THX to{ void NavigateTo(Uri pageUri); Laurent Bugnion}public class NavigationService : INavigationService{ private static PhoneApplicationFrame _mainFrame; public event NavigatingCancelEventHandler Navigating; public void NavigateTo(Uri pageUri) { … }}
  66. 66. TDD [Test] public void ShowDetail_Should_NavigateToDetailView() { var navigationService = new Mock<INavigationService>(); var searchService = new Mock<ISearchService>(); var viewModel = new MainViewModel(searchService.Object,navigationService.Object); viewModel.ShowDetail.Execute(new Track{Id=345}); navigationService.Verify(p => p.NavigateTo(new Uri("/View/DetailView.xaml?id=345", UriKind.Relative)));}
  67. 67. TDD [Test] public void ShowDetail_Should_NavigateToDetailView() { var navigationService = new Mock<INavigationService>(); var searchService = new Mock<ISearchService>(); var viewModel = new MainViewModel(searchService.Object,navigationService.Object); viewModel.ShowDetail.Execute(new Track{Id=345}); navigationService.Verify(p => p.NavigateTo(newUri("/View/DetailView.xaml?id=345", UriKind.Relative)));}
  68. 68. TDD [Test] public void ShowDetail_Should_NavigateToDetailView() { var navigationService = new Mock<INavigationService>(); var searchService = new Mock<ISearchService>(); var viewModel = new MainViewModel(searchService.Object,navigationService.Object); viewModel.ShowDetail.Execute(new Track{Id=345}); navigationService.Verify(p => p.NavigateTo(newUri("/View/DetailView.xaml?id=345", UriKind.Relative)));}
  69. 69. TDD [Test] public void ShowDetail_Should_NavigateToDetailView() { var navigationService = new Mock<INavigationService>(); var searchService = new Mock<ISearchService>(); var viewModel = new MainViewModel(searchService.Object,navigationService.Object); viewModel.ShowDetail.Execute(new Track{Id=345}); navigationService.Verify(p => p.NavigateTo(newUri("/View/DetailView.xaml?id=345", UriKind.Relative)));}
  70. 70. TDD - Redpublic class MainViewModel{ private IList<Track> _tracks; public IList<Track> Tracks { get { return _tracks; } } public string SearchedText { get; set; } public DelegateCommand Search { get; private set; } public DelegateCommand<Track> ShowDetail{get; set; }
  71. 71. TDD - Redpublic MainViewModel(ISearchService searchService,INavigationService navigationService) { _searchService = searchService; _navigationService = navigationService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch); ShowDetail= new DelegateCommand<Track>(OnShowDetail); }
  72. 72. TDD - Redpublic MainViewModel(ISearchService searchService,INavigationService navigationService) { _searchService = searchService; _navigationService = navigationService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch); ShowDetail= new DelegateCommand<Track>(OnShowDetail); }
  73. 73. TDD - Red
  74. 74. TDD - Greenprivate readonly INavigationService _navigationService;…public DelegateCommand<Track> ShowDetail{get; set; }… public MainViewModel(ISearchService searchService,INavigationService navigationService) { _searchService = searchService; _navigationService = navigationService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch); ShowDetail= new DelegateCommand<Track>(OnShowDetail); }
  75. 75. TDD - Greenprivate void OnSearch(){ _tracks= _searchService.SearchUserTrack(SearchedText);}private void OnShowDetail(Track obj){ _navigationService.NavigateTo(new Uri("/View/DetailView.xaml?id="+obj.Id, UriKind.Relative));}
  76. 76. TDD - Green
  77. 77. TDD - Refactorprivate readonly INavigationService _navigationService;public DelegateCommand<Track> ShowDetail{get; private set; }public MainViewModel(ISearchService searchService,INavigationService navigationService) { _searchService = searchService; _navigationService = navigationService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch); ShowDetail= new DelegateCommand<Track>(OnShowDetail); }
  78. 78. TDD - Refactorprivate void OnSearch(){ _tracks= _searchService.SearchUserTrack(SearchedText);}private void OnShowDetail(Track track){ _navigationService.NavigateTo(new Uri("/View/DetailView.xaml?id=”+track.Id, UriKind.Relative));}
  79. 79. TDD - Refactor
  80. 80. TDD – Test suite refactor [Test] public void ShowDetail_Should_NavigateToDetailView() { var navigationService = new Mock<INavigationService>(); var searchService = new Mock<ISearchService>(); var viewModel = new MainViewModel(searchService.Object,navigationService.Object); viewModel.ShowDetail.Execute(new Track{Id=345}); navigationService.Verify(p => p.NavigateTo(newUri("/View/DetailView.xaml?id=345", UriKind.Relative)));}
  81. 81. TDD – Test suite refactor [Test] public void ShowDetail_Should_NavigateToDetailView() { var navigationService = new Mock<INavigationService>(); var searchService = new Mock<ISearchService>(); var viewModel = new MainViewModel(searchService.Object,navigationService.Object); viewModel.ShowDetail.Execute(new Track{Id=345}); navigationService.Verify(p => p.NavigateTo(newUri("/View/DetailView.xaml?id=345", UriKind.Relative)));}
  82. 82. TDD – Test suite refactorpublic class MainViewModelFixture{ private Mock<INavigationService> _navigationService; private Mock<ISearchService> _searchService; private MainViewModel _viewModel; [SetUp] public void Setup() { _navigationService = new Mock<INavigationService>(); _searchService = new Mock<ISearchService>(); _viewModel = new MainViewModel(_searchService.Object,_navigationService.Object); }
  83. 83. TDD – Test suite refactorpublic class MainViewModelFixture{ private Mock<INavigationService> _navigationService; private Mock<ISearchService> _searchService; private MainViewModel _viewModel; [SetUp] public void Setup() { _navigationService = new Mock<INavigationService>(); _searchService = new Mock<ISearchService>(); _viewModel = new MainViewModel(_searchService.Object,_navigationService.Object); }
  84. 84. ViewModel and UI• FrameworkElement.DataContext• “A directly embedded object that serves as data context for any bindings within the parent element”• We’ll put here our ViewModel!<phone:PhoneApplicationPage DataContext=“”/>
  85. 85. ViewModel and UIpublic partial class MainView :PhoneApplicationPage{ public MainView() { InitializeComponent(); DataContext = new MainViewModel(new SearchService(),new NavigationService()); }}
  86. 86. MainView<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <TextBox Text="{Binding Text,Mode=TwoWay}” /> <Button Content="Search" Command="{BindingSearch}" HorizontalAlignment="Right" > </StackPanel>
  87. 87. MainView<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <TextBox Text="{Binding Text,Mode=TwoWay}” /> <Button Content="Search" Command="{BindingSearch}" HorizontalAlignment="Right" > </StackPanel>
  88. 88. MainView<ItemsControl Grid.Row="1" ItemsSource="{Binding Tracks}” > <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Tap="ShowDetail"> <Image Source="{Binding Image}" /> <TextBlock Text="{Binding Title}"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate></ItemsControl>
  89. 89. MainView<ItemsControl Grid.Row="1" ItemsSource="{Binding Tracks}” > <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Tap="ShowDetail"> <Image Source="{Binding Image}" /> <TextBlock Text="{Binding Title}"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate></ItemsControl>
  90. 90. INotifyPropertyChanged• INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.
  91. 91. INotifyPropertyChangedpublic class MainViewModel : INotifyPropertyChanged{ public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } }
  92. 92. INotifyPropertyChanged private void ExecuteSearch() { _tracks=_service.SearchUserTrack(SearchedUser); NotifyPropertyChanged(”Tracks"); }}
  93. 93. RecapWhat we have seen:-TDD (unit test, mock)-MVVM (commanding, binding,INotifyPropertyChanged, DataContext)
  94. 94. Node.JS
  95. 95. Be in contactMail: michele@orangecode.itTwitter: @piccoloaiutanteWeb: www.orangecode.itBlog: www.orangecode.it/blogGitHub: https://github.com/piccoloaiutanteCommunity: WEBdeBS
  96. 96. That’s all folks

×