SlideShare a Scribd company logo
1 of 96
Sviluppare un'app 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
Track
public 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; }
}
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>
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>
Xaml


<StackPanel Orientation="Horizontal">
 <TextBox x:Name="searchedText" />
 <Button Content="Search" Click="Search" />
</StackPanel>
Xaml
<ItemsControl x:Name="songsList">
   <ItemsControl.ItemTemplate>
    <DataTemplate>
       <StackPanel Orientation="Horizontal">
        <Image Source="{Binding Image}”/>
        <TextBlock Text="{Binding Title}"/>
       </StackPanel>
     </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>
Code behind MainView
public 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));
      }
  }
Code behind MainView
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
       };
Code behind MainView
 client.ExecuteAsync<List<Track>>(request, response =>
    {
       songsList.ItemsSource = response.Data;
    });
}
Code behind MainView

private void ShowDetail(object sender, GestureEventArgs e)
{
        NavigationService.Navigate(
               new Uri(
                   "/View/DetailView.xaml?id="+
                   ((Track)((StackPanel)sender).DataContext).Id,
                   UriKind.Relative
                   )
       );
}
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>
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>
Code behind DetailView
public 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;

         });
     }
 }
Code behind DetailView
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
       };
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;

    });
}
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 Logic



       UI                                               ViewModel

             Collections, DelegateCommand, Properties
MVVM approach
• Structure our code:
  – ViewModel (c#): Logic
  – View (Xaml): Presentation
  – No more code behind
• Now the ViewModel is testable
Test Driven Development
• As easy as complex

• Life Cycle:
  – Write test (red)
  – Write logic to pass the test (green)
  – Refactor code (refactor)
  – Again..
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
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!
TDD
• Download searched user songs list
  from SoundCloud.com
TDD
• There is a list of track that i’ve to
  show
TDD
namespace OrangeCode.SoundCloudFixture
{
  public class MainViewModelFixture
  {
  }
}

namespace OrangeCode.SoundCloud
{
  public class MainViewModel
  {
  }
}
TDD -Red
Write test:
   [Test]
   public void Constructor_Should_Initialize_TrackList()
   {
     MainViewModel viewModel = new MainViewModel();
     Assert.IsNotNull(viewModel.Tracks);
   }
TDD
You are not allowed to write any
production code unless it is to make a
failing unit test pass.

                    Uncle Bob Martin
TDD - Red

public class MainViewModel
{
  public IList<Track> Tracks
  {
      get ;
      set ;
  }
}
TDD
TDD
You are not allowed to write any more
production code than is sufficient to
pass the one failing unit test.

                   Uncle Bob Martin
TDD - Green

public class MainViewModel
{
  public IList<Track> Tracks { get; set; }

    public MainViewModel()
    {
      Tracks = new List<Track>();
    }
}
TDD
TDD –Refactor
public class MainViewModel{

    private IList<Track> _tracks;

    public IList<Track> Tracks
    {
      get { return _tracks; }
    }

    public MainViewModel()
    {
      _tracks = new List<Track>();
    }
}
TDD - Refactor
TDD
• Download searched user songs list
  from SoundCloud.com
Architecture
   Main
ViewModel




      Ilist<Track>SearchUserTrack(string
      )




 Search             Rest Call
 Service
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
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"));
}
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"));
}
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.
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"));
}
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.
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>
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"));
}
TDD - Red
Add properties in order to compile

public string SearchedText { get; set; }

public DelegateCommand Search { get; set; }
TDD - Red
TDD - Green
public 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);
}
TDD - Green
TDD - Refactor
public 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);
}
TDD - Refactor
TDD
• Display the list
TDD
[Test]
public void Search_Should_UpdateTrackList()
{
  _searchService.Setup(p =>
p.SearchUserTrack("michelecapra")).Returns(new List<Track>{new
Track()});

    _viewModel.SearchedText = "michelecapra";
    _viewModel.Search.Execute();

    Assert.AreEqual(_viewModel.Tracks.Count, 1);
}
TDD
[Test]
public void Search_Should_UpdateTrackList()
{
  _searchService.Setup(p =>
p.SearchUserTrack("michelecapra")).Returns(new List<Track>{new
Track()});

    _viewModel.SearchedText = "michelecapra";
    _viewModel.Search.Execute();

    Assert.AreEqual(_viewModel.Tracks.Count, 1);
}
TDD
[Test]
public void Search_Should_UpdateTrackList()
{
  _searchService.Setup(p =>
p.SearchUserTrack("michelecapra")).Returns(new List<Track>{new
Track()});

    _viewModel.SearchedText = "michelecapra";
    _viewModel.Search.Execute();

    Assert.AreEqual(_viewModel.Tracks.Count, 1);
}
TDD - Red
public 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);
}
TDD - Red
TDD - Green
private 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 Service
public 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) { … }
}
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)));

}
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)));

}
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)));

}
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)));

}
TDD - Red
public 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; }
TDD - Red
public MainViewModel(ISearchService searchService,
INavigationService navigationService)
 {
    _searchService = searchService;
    _navigationService = navigationService;
    _tracks = new List<Track>();
    Search = new DelegateCommand(OnSearch);
    ShowDetail= new DelegateCommand<Track>(OnShowDetail);
  }
TDD - Red
public MainViewModel(ISearchService searchService,
INavigationService navigationService)
 {
    _searchService = searchService;
    _navigationService = navigationService;
    _tracks = new List<Track>();
    Search = new DelegateCommand(OnSearch);
    ShowDetail= new DelegateCommand<Track>(OnShowDetail);
  }
TDD - Red
TDD - Green
private 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);
  }
TDD - Green
private void OnSearch()
{
  _tracks= _searchService.SearchUserTrack(SearchedText);
}

private void OnShowDetail(Track obj)
{
   _navigationService.NavigateTo(new Uri("/View/DetailView.xaml?
id="+obj.Id, UriKind.Relative));
}
TDD - Green
TDD - Refactor
private 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);
  }
TDD - Refactor
private void OnSearch()
{
  _tracks= _searchService.SearchUserTrack(SearchedText);
}

private void OnShowDetail(Track track)
{
   _navigationService.NavigateTo(new Uri("/View/DetailView.xaml?
id=”+track.Id, UriKind.Relative));
}
TDD - Refactor
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(new
Uri("/View/DetailView.xaml?id=345", UriKind.Relative)));

}
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(new
Uri("/View/DetailView.xaml?id=345", UriKind.Relative)));

}
TDD – Test suite refactor
public 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);
   }
TDD – Test suite refactor
public 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);
   }
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=“”/>
ViewModel and UI
public partial class MainView :PhoneApplicationPage
{
     public MainView()
     {
        InitializeComponent();
        DataContext = new MainViewModel(new SearchService(),
new NavigationService());
     }
}
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="{Binding
Search}" HorizontalAlignment="Right" >
   </StackPanel>
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="{Binding
Search}" HorizontalAlignment="Right" >
   </StackPanel>
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>
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>
INotifyPropertyChanged
• INotifyPropertyChanged interface is
  used to notify clients, typically
  binding clients, that a property value
  has changed.
INotifyPropertyChanged
public class MainViewModel : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

 private void NotifyPropertyChanged(String name)
 {
   if (PropertyChanged != null)
   {
     PropertyChanged(this, new PropertyChangedEventArgs(name));
   }
 }
INotifyPropertyChanged
 private void ExecuteSearch()
 {
   _tracks=_service.SearchUserTrack(SearchedUser);
   NotifyPropertyChanged(”Tracks");
 }
}
Recap
What we have seen:
-TDD (unit test, mock)
-MVVM (commanding, binding,
INotifyPropertyChanged, DataContext)
Node.JS
Be in contact

Mail: michele@orangecode.it
Twitter: @piccoloaiutante
Web: www.orangecode.it
Blog: www.orangecode.it/blog
GitHub: https://github.com/piccoloaiutante

Community: WEBdeBS
That’s all folks

More Related Content

What's hot

Advanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceAdvanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceNiraj Bharambe
 
Hibernate
Hibernate Hibernate
Hibernate Sunil OS
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackGaryCoady
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented NetworkingMostafa Amer
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4DEVCON
 
Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4DEVCON
 
Data Binding Intro (Windows 8)
Data Binding Intro (Windows 8)Data Binding Intro (Windows 8)
Data Binding Intro (Windows 8)Gilbok Lee
 
Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots DeepAnshu Sharma
 
Source Code for Dpilot
Source Code for Dpilot Source Code for Dpilot
Source Code for Dpilot Nidhi Chauhan
 
Mastering Oracle ADF Bindings
Mastering Oracle ADF BindingsMastering Oracle ADF Bindings
Mastering Oracle ADF BindingsEuegene Fedorenko
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleVladimir Kostyukov
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Ryosuke Uchitate
 
React, Redux and es6/7
React, Redux and es6/7React, Redux and es6/7
React, Redux and es6/7Dongho Cho
 
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...Knoldus Inc.
 
ERRest - The Next Steps
ERRest - The Next StepsERRest - The Next Steps
ERRest - The Next StepsWO Community
 
Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4DEVCON
 

What's hot (20)

Advanced java practical semester 6_computer science
Advanced java practical semester 6_computer scienceAdvanced java practical semester 6_computer science
Advanced java practical semester 6_computer science
 
Hibernate
Hibernate Hibernate
Hibernate
 
ERRest
ERRestERRest
ERRest
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4
 
Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4Python Code Camp for Professionals 4/4
Python Code Camp for Professionals 4/4
 
JavaScript JQUERY AJAX
JavaScript JQUERY AJAXJavaScript JQUERY AJAX
JavaScript JQUERY AJAX
 
Data Binding Intro (Windows 8)
Data Binding Intro (Windows 8)Data Binding Intro (Windows 8)
Data Binding Intro (Windows 8)
 
Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots
 
Source Code for Dpilot
Source Code for Dpilot Source Code for Dpilot
Source Code for Dpilot
 
Mastering Oracle ADF Bindings
Mastering Oracle ADF BindingsMastering Oracle ADF Bindings
Mastering Oracle ADF Bindings
 
Ad java prac sol set
Ad java prac sol setAd java prac sol set
Ad java prac sol set
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with Finagle
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
 
React, Redux and es6/7
React, Redux and es6/7React, Redux and es6/7
React, Redux and es6/7
 
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
 
ERRest - The Next Steps
ERRest - The Next StepsERRest - The Next Steps
ERRest - The Next Steps
 
Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 

Viewers also liked

Mobile application
Mobile applicationMobile application
Mobile applicationenunmint
 
Biografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato bBiografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato bBryan100500
 
Mobile application
Mobile applicationMobile application
Mobile applicationenunmint
 
Getting started with Windows Phone 7 and unit test
Getting started with Windows Phone 7 and unit testGetting started with Windows Phone 7 and unit test
Getting started with Windows Phone 7 and unit testMichele Capra
 
Biografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato bBiografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato bBryan100500
 
Introduzione a Node.js
Introduzione a Node.jsIntroduzione a Node.js
Introduzione a Node.jsMichele Capra
 
Taller SENA RAEE
Taller SENA RAEETaller SENA RAEE
Taller SENA RAEEestebanfg13
 
Requisitos para inconformidades textos. solo vista.docx
Requisitos para inconformidades textos. solo vista.docx Requisitos para inconformidades textos. solo vista.docx
Requisitos para inconformidades textos. solo vista.docx SEV
 
Presentación Elena Dinesen, Directora RRHH Microsoft España
Presentación Elena Dinesen, Directora RRHH Microsoft EspañaPresentación Elena Dinesen, Directora RRHH Microsoft España
Presentación Elena Dinesen, Directora RRHH Microsoft EspañaJordi Assens
 
No dejes de volar en la ruta digital (2010)
No dejes de volar en la ruta digital (2010)No dejes de volar en la ruta digital (2010)
No dejes de volar en la ruta digital (2010)Nieves Gonzalez
 
Web móvil: ¿inclusiva y accesible?
Web móvil: ¿inclusiva y accesible?Web móvil: ¿inclusiva y accesible?
Web móvil: ¿inclusiva y accesible?Hernan Beati
 
How Banks Can Use Social Media Analytics To Drive Business Advantage
How Banks Can Use Social Media Analytics To Drive Business AdvantageHow Banks Can Use Social Media Analytics To Drive Business Advantage
How Banks Can Use Social Media Analytics To Drive Business AdvantageCognizant
 
Musica Pawer Point O[1][1].T
Musica Pawer Point O[1][1].TMusica Pawer Point O[1][1].T
Musica Pawer Point O[1][1].Ttheblackbubbles
 
Hera Group Sustainability Report 2010
Hera Group Sustainability Report 2010Hera Group Sustainability Report 2010
Hera Group Sustainability Report 2010Hera Group
 
Funcionamiento básico de una computadora
Funcionamiento básico de una computadoraFuncionamiento básico de una computadora
Funcionamiento básico de una computadoraAlex Dib
 
Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...
Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...
Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...Juhász István
 
S C H W E I Z 2
S C H W E I Z 2S C H W E I Z 2
S C H W E I Z 2avrelij
 

Viewers also liked (20)

Mobile application
Mobile applicationMobile application
Mobile application
 
Biografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato bBiografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato b
 
Mobile application
Mobile applicationMobile application
Mobile application
 
Getting started with Windows Phone 7 and unit test
Getting started with Windows Phone 7 and unit testGetting started with Windows Phone 7 and unit test
Getting started with Windows Phone 7 and unit test
 
Biografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato bBiografia bryan mena 1 bachillerato b
Biografia bryan mena 1 bachillerato b
 
Introduzione a Node.js
Introduzione a Node.jsIntroduzione a Node.js
Introduzione a Node.js
 
Taller SENA RAEE
Taller SENA RAEETaller SENA RAEE
Taller SENA RAEE
 
Brochure Italian Language School Italy 2011
Brochure Italian Language School Italy 2011Brochure Italian Language School Italy 2011
Brochure Italian Language School Italy 2011
 
Terminal portuario Juan Fernández
Terminal portuario Juan FernándezTerminal portuario Juan Fernández
Terminal portuario Juan Fernández
 
Requisitos para inconformidades textos. solo vista.docx
Requisitos para inconformidades textos. solo vista.docx Requisitos para inconformidades textos. solo vista.docx
Requisitos para inconformidades textos. solo vista.docx
 
Presentación Elena Dinesen, Directora RRHH Microsoft España
Presentación Elena Dinesen, Directora RRHH Microsoft EspañaPresentación Elena Dinesen, Directora RRHH Microsoft España
Presentación Elena Dinesen, Directora RRHH Microsoft España
 
No dejes de volar en la ruta digital (2010)
No dejes de volar en la ruta digital (2010)No dejes de volar en la ruta digital (2010)
No dejes de volar en la ruta digital (2010)
 
Web móvil: ¿inclusiva y accesible?
Web móvil: ¿inclusiva y accesible?Web móvil: ¿inclusiva y accesible?
Web móvil: ¿inclusiva y accesible?
 
How Banks Can Use Social Media Analytics To Drive Business Advantage
How Banks Can Use Social Media Analytics To Drive Business AdvantageHow Banks Can Use Social Media Analytics To Drive Business Advantage
How Banks Can Use Social Media Analytics To Drive Business Advantage
 
Musica Pawer Point O[1][1].T
Musica Pawer Point O[1][1].TMusica Pawer Point O[1][1].T
Musica Pawer Point O[1][1].T
 
Hera Group Sustainability Report 2010
Hera Group Sustainability Report 2010Hera Group Sustainability Report 2010
Hera Group Sustainability Report 2010
 
Funcionamiento básico de una computadora
Funcionamiento básico de una computadoraFuncionamiento básico de una computadora
Funcionamiento básico de una computadora
 
51237 - UN 752 SEPTEMBRE 2015_BD (1)
51237 - UN 752 SEPTEMBRE 2015_BD (1)51237 - UN 752 SEPTEMBRE 2015_BD (1)
51237 - UN 752 SEPTEMBRE 2015_BD (1)
 
Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...
Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...
Korszerű innovatív megoldások a marketingkommunikációban-Az okos telefonok je...
 
S C H W E I Z 2
S C H W E I Z 2S C H W E I Z 2
S C H W E I Z 2
 

Similar to Developing application for Windows Phone 7 in TDD

Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networkingVitali Pekelis
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!DataArt
 
Summer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and ScalaSummer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and Scalarostislav
 
The Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIThe Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIEyal Vardi
 
MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know Norberto Leite
 
Mongo+java (1)
Mongo+java (1)Mongo+java (1)
Mongo+java (1)MongoDB
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
Building Modern Websites with ASP.NET by Rachel Appel
Building Modern Websites with ASP.NET by Rachel AppelBuilding Modern Websites with ASP.NET by Rachel Appel
Building Modern Websites with ASP.NET by Rachel Appel.NET Conf UY
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to TornadoGavin Roy
 
GraphTour - Utilizing Powerful Extensions for Analytics & Operations
GraphTour - Utilizing Powerful Extensions for Analytics & OperationsGraphTour - Utilizing Powerful Extensions for Analytics & Operations
GraphTour - Utilizing Powerful Extensions for Analytics & OperationsNeo4j
 
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...Fons Sonnemans
 
Domain-Driven Design with SeedStack
Domain-Driven Design with SeedStackDomain-Driven Design with SeedStack
Domain-Driven Design with SeedStackSeedStack
 
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and OperationsNeo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and OperationsMark Needham
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiqueDenis Voituron
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsHassan Abid
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with SwagJens Ravens
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
Revolution or Evolution in Page Object
Revolution or Evolution in Page ObjectRevolution or Evolution in Page Object
Revolution or Evolution in Page ObjectArtem Sokovets
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Eyal Vardi
 

Similar to Developing application for Windows Phone 7 in TDD (20)

Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
Summer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and ScalaSummer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and Scala
 
The Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIThe Full Power of ASP.NET Web API
The Full Power of ASP.NET Web API
 
MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know
 
Mongo+java (1)
Mongo+java (1)Mongo+java (1)
Mongo+java (1)
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Building Modern Websites with ASP.NET by Rachel Appel
Building Modern Websites with ASP.NET by Rachel AppelBuilding Modern Websites with ASP.NET by Rachel Appel
Building Modern Websites with ASP.NET by Rachel Appel
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
 
GraphTour - Utilizing Powerful Extensions for Analytics & Operations
GraphTour - Utilizing Powerful Extensions for Analytics & OperationsGraphTour - Utilizing Powerful Extensions for Analytics & Operations
GraphTour - Utilizing Powerful Extensions for Analytics & Operations
 
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
 
Domain-Driven Design with SeedStack
Domain-Driven Design with SeedStackDomain-Driven Design with SeedStack
Domain-Driven Design with SeedStack
 
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and OperationsNeo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with Swag
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Revolution or Evolution in Page Object
Revolution or Evolution in Page ObjectRevolution or Evolution in Page Object
Revolution or Evolution in Page Object
 
UIWebView Tips
UIWebView TipsUIWebView Tips
UIWebView Tips
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)
 

More from Michele Capra

Nodeschool italy at codemotion
Nodeschool italy at codemotionNodeschool italy at codemotion
Nodeschool italy at codemotionMichele Capra
 
Little bits & node.js IOT for beginner
Little bits & node.js IOT for beginnerLittle bits & node.js IOT for beginner
Little bits & node.js IOT for beginnerMichele Capra
 
Testing Windows Phone 8.1 app with unit test and Coded UI test
Testing Windows Phone 8.1 app with unit test and Coded UI testTesting Windows Phone 8.1 app with unit test and Coded UI test
Testing Windows Phone 8.1 app with unit test and Coded UI testMichele Capra
 
Porting business apps to Windows Phone
Porting business apps to Windows PhonePorting business apps to Windows Phone
Porting business apps to Windows PhoneMichele Capra
 
The magic of Dynamic in Nancy Fx
The magic of Dynamic in Nancy FxThe magic of Dynamic in Nancy Fx
The magic of Dynamic in Nancy FxMichele Capra
 
Windows Phone 7 Development
Windows Phone 7 DevelopmentWindows Phone 7 Development
Windows Phone 7 DevelopmentMichele Capra
 
My Final Dissertation
My Final DissertationMy Final Dissertation
My Final DissertationMichele Capra
 

More from Michele Capra (7)

Nodeschool italy at codemotion
Nodeschool italy at codemotionNodeschool italy at codemotion
Nodeschool italy at codemotion
 
Little bits & node.js IOT for beginner
Little bits & node.js IOT for beginnerLittle bits & node.js IOT for beginner
Little bits & node.js IOT for beginner
 
Testing Windows Phone 8.1 app with unit test and Coded UI test
Testing Windows Phone 8.1 app with unit test and Coded UI testTesting Windows Phone 8.1 app with unit test and Coded UI test
Testing Windows Phone 8.1 app with unit test and Coded UI test
 
Porting business apps to Windows Phone
Porting business apps to Windows PhonePorting business apps to Windows Phone
Porting business apps to Windows Phone
 
The magic of Dynamic in Nancy Fx
The magic of Dynamic in Nancy FxThe magic of Dynamic in Nancy Fx
The magic of Dynamic in Nancy Fx
 
Windows Phone 7 Development
Windows Phone 7 DevelopmentWindows Phone 7 Development
Windows Phone 7 Development
 
My Final Dissertation
My Final DissertationMy Final Dissertation
My Final Dissertation
 

Recently uploaded

Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...AliaaTarek5
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 

Recently uploaded (20)

Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 

Developing application for Windows Phone 7 in TDD

  • 1. Sviluppare un'app per WP7 in TDD? Si può fare!
  • 2. Who am I? • Developer freelance: – C# Asp.net Mvc, Wpf, Wp7 – Python Django – Blog: orangecode.it/blog • WEBdeBS founder
  • 3. What we’re going to see • TDD • MVVM • Code.. • Code… • …some more code!
  • 4. The show case • Basic application • Download user songs list from SoundCloud.com • Display the list • View song’s detail
  • 6. Let’s do it with code behind
  • 7. Track public 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. 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. 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. Xaml <StackPanel Orientation="Horizontal"> <TextBox x:Name="searchedText" /> <Button Content="Search" Click="Search" /> </StackPanel>
  • 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. Code behind MainView public 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. Code behind MainView 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 };
  • 14. Code behind MainView client.ExecuteAsync<List<Track>>(request, response => { songsList.ItemsSource = response.Data; }); }
  • 15. Code behind MainView private void ShowDetail(object sender, GestureEventArgs e) { NavigationService.Navigate( new Uri( "/View/DetailView.xaml?id="+ ((Track)((StackPanel)sender).DataContext).Id, UriKind.Relative ) ); }
  • 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. 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. Code behind DetailView public 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. Code behind DetailView 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 };
  • 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. Problem with code behind • Code coupled with UI – Xaml + Code Behind -> one class • Not testable
  • 22. MVVM approach • Architectural Pattern • Derived from Presentation Model pattern (Fowler) • Clear separation between UI and Logic UI ViewModel Collections, DelegateCommand, Properties
  • 23. MVVM approach • Structure our code: – ViewModel (c#): Logic – View (Xaml): Presentation – No more code behind • Now the ViewModel is testable
  • 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. 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. 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. TDD • Download searched user songs list from SoundCloud.com
  • 28. TDD • There is a list of track that i’ve to show
  • 29. TDD namespace OrangeCode.SoundCloudFixture { public class MainViewModelFixture { } } namespace OrangeCode.SoundCloud { public class MainViewModel { } }
  • 30. TDD -Red Write test: [Test] public void Constructor_Should_Initialize_TrackList() { MainViewModel viewModel = new MainViewModel(); Assert.IsNotNull(viewModel.Tracks); }
  • 31. TDD You are not allowed to write any production code unless it is to make a failing unit test pass. Uncle Bob Martin
  • 32. TDD - Red public class MainViewModel { public IList<Track> Tracks { get ; set ; } }
  • 33. TDD
  • 34. TDD You are not allowed to write any more production code than is sufficient to pass the one failing unit test. Uncle Bob Martin
  • 35. TDD - Green public class MainViewModel { public IList<Track> Tracks { get; set; } public MainViewModel() { Tracks = new List<Track>(); } }
  • 36. TDD
  • 37. TDD –Refactor public class MainViewModel{ private IList<Track> _tracks; public IList<Track> Tracks { get { return _tracks; } } public MainViewModel() { _tracks = new List<Track>(); } }
  • 39. TDD • Download searched user songs list from SoundCloud.com
  • 40. Architecture Main ViewModel Ilist<Track>SearchUserTrack(string ) Search Rest Call Service
  • 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. 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. 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. 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. 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. 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. 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. 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. TDD - Red Add properties in order to compile public string SearchedText { get; set; } public DelegateCommand Search { get; set; }
  • 51. TDD - Green public 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); }
  • 53. TDD - Refactor public 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); }
  • 56. TDD [Test] public void Search_Should_UpdateTrackList() { _searchService.Setup(p => p.SearchUserTrack("michelecapra")).Returns(new List<Track>{new Track()}); _viewModel.SearchedText = "michelecapra"; _viewModel.Search.Execute(); Assert.AreEqual(_viewModel.Tracks.Count, 1); }
  • 57. TDD [Test] public void Search_Should_UpdateTrackList() { _searchService.Setup(p => p.SearchUserTrack("michelecapra")).Returns(new List<Track>{new Track()}); _viewModel.SearchedText = "michelecapra"; _viewModel.Search.Execute(); Assert.AreEqual(_viewModel.Tracks.Count, 1); }
  • 58. TDD [Test] public void Search_Should_UpdateTrackList() { _searchService.Setup(p => p.SearchUserTrack("michelecapra")).Returns(new List<Track>{new Track()}); _viewModel.SearchedText = "michelecapra"; _viewModel.Search.Execute(); Assert.AreEqual(_viewModel.Tracks.Count, 1); }
  • 59. TDD - Red public 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); }
  • 61. TDD - Green private void OnSearch() { _tracks= _searchService.SearchUserTrack(SearchedText); }
  • 64. TDD • We need to introduce the NavigationService • But how to decouple it from our ViewModel?
  • 65. TDD – Navigation Service public 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. 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. 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))); }
  • 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(new Uri("/View/DetailView.xaml?id=345", UriKind.Relative))); }
  • 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(new Uri("/View/DetailView.xaml?id=345", UriKind.Relative))); }
  • 70. TDD - Red public 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. TDD - Red public MainViewModel(ISearchService searchService, INavigationService navigationService) { _searchService = searchService; _navigationService = navigationService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch); ShowDetail= new DelegateCommand<Track>(OnShowDetail); }
  • 72. TDD - Red public MainViewModel(ISearchService searchService, INavigationService navigationService) { _searchService = searchService; _navigationService = navigationService; _tracks = new List<Track>(); Search = new DelegateCommand(OnSearch); ShowDetail= new DelegateCommand<Track>(OnShowDetail); }
  • 74. TDD - Green private 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. TDD - Green private void OnSearch() { _tracks= _searchService.SearchUserTrack(SearchedText); } private void OnShowDetail(Track obj) { _navigationService.NavigateTo(new Uri("/View/DetailView.xaml? id="+obj.Id, UriKind.Relative)); }
  • 77. TDD - Refactor private 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. TDD - Refactor private void OnSearch() { _tracks= _searchService.SearchUserTrack(SearchedText); } private void OnShowDetail(Track track) { _navigationService.NavigateTo(new Uri("/View/DetailView.xaml? id=”+track.Id, UriKind.Relative)); }
  • 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(new Uri("/View/DetailView.xaml?id=345", UriKind.Relative))); }
  • 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(new Uri("/View/DetailView.xaml?id=345", UriKind.Relative))); }
  • 82. TDD – Test suite refactor public 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. TDD – Test suite refactor public 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. 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. ViewModel and UI public partial class MainView :PhoneApplicationPage { public MainView() { InitializeComponent(); DataContext = new MainViewModel(new SearchService(), new NavigationService()); } }
  • 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="{Binding Search}" HorizontalAlignment="Right" > </StackPanel>
  • 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="{Binding Search}" HorizontalAlignment="Right" > </StackPanel>
  • 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. 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. INotifyPropertyChanged • INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.
  • 91. INotifyPropertyChanged public class MainViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } }
  • 92. INotifyPropertyChanged private void ExecuteSearch() { _tracks=_service.SearchUserTrack(SearchedUser); NotifyPropertyChanged(”Tracks"); } }
  • 93. Recap What we have seen: -TDD (unit test, mock) -MVVM (commanding, binding, INotifyPropertyChanged, DataContext)
  • 95. Be in contact Mail: michele@orangecode.it Twitter: @piccoloaiutante Web: www.orangecode.it Blog: www.orangecode.it/blog GitHub: https://github.com/piccoloaiutante Community: WEBdeBS

Editor's Notes

  1. Applicazione base: Dato un utente di soundcloud scaricare la lista delle sue canzoni pubblicate Mostrarla nella schermata principale Cliccando sulla canzone mostrare I suoi dettagli, come l’immagine e la data di pubblicazione E’ solo un esempio giusto per avere qualcosa su cui discutere
  2. Ecco le due schermate: La prima con liste delle canzoni box e tasto per cercare La seconda dove mostro I dettagli della canzone Non mi sono messo molto sulla grafica perchè ci server solo per lavorare
  3. Proviamo a fare l’applicazione in modo tradizionale
  4. Il tipo di dato che andrò a scaricare da SoundCloud è formato così Ho preso un subset di tutte le informazioni che SoundCloud espone per ogni brano
  5. View semplicficata Ho tolto alcuni tag xaml per questioni di spazio sulla slide
  6. View semplicficata Ho tolto alcuni tag xaml per questioni di spazio sulla slide
  7. Parte in alto Una textbox per inserire il nome dell’artista da cercare Un tasto search per effettuare la ricerca e scaricare I dati
  8. Un itemcontrol che mostra I brani scaricati
  9. Vediamo che cosa viene fatto nel code behind
  10. Utilizzo RestSharp che è un componente per poter effettuare la manipolazione di risorse esposte tramite REST. Definisco l’url su cui lavorare Definisco la rappresentazione della risorsa la voglio in json
  11. Effettuo la chiamata vera e propria il risultato lo carico come itemsource delll’itemcontrol
  12. Definisco il metodo che verrà chiamato quando seleziono una canzone Utilizzo il NavigationService di silverlight per spostarmi nella prossima pagina Passo come parametro alla pagina l’id della canzone che ho selezionato
  13. In questa vista mostro il dettaglio della canzone che ho selezionato
  14. Sostanzialmente mostro l’immagine collegata alla canzone data di creazione Titolo descrizione
  15. Mi aggancio all’evento di navigazione in ingresso alla pagina Reperisco l’id E imposto la chiamata rest
  16. Deserializzo le informazioni reperite E le carico nei controlli
  17. Problemi con questo approccio Codice fortemente accoppiato con l’interfaccia Lo xaml e il code behind di fatto diventano una classe sola (partial) Quindi il codice non è testabile
  18. Per ultima cosa - Mostrare come viene aganciato il viewmodel alla vista
  19. Proviamo a farlo in tdd Questa volta avremo due classi separate: Il viewmodel dovee mettiamo tutta la logica dell’applicazione Lo xaml solo per la presentazione Niente più code behind
  20. In se non è molto difficile Pensare alla funzionalità su cui si sta lavorando Scrivere in modo dichiarativo il test Verificare che sia rotto Scrivere il codice per farlo passare Verificare che il test sia passato Fare refactor del codice scritto Per il refactor vi consiglio il libro di Fowler
  21. Non voglio dilungarmi sul tdd e sul perchè farlo Giusto due cose Tdd serve per ottenere un miglior design del codice I test sono un ottimo effetto collaterale del tdd Disciplina e pratica
  22. Nunit come framework di unit test Moq 3.1 per silverlight funziona su wp7
  23. Partiamo con la prima storia Voglio scaricare le canzoni di un utente che è stato cercato da Soundcloud
  24. immagino che ci sia una lista,intesa come struttura dati che devo mostrare Difficile partire con I test Quindi stupidamente quasi giusto per partire penso che questa lista dovrà essere inizializzata
  25. - Faccio questo perchè ho visto spesso che partire è una delle cose piu difficili quando ci si trova di fronte a questo
  26. Faccio questo perchè ho visto spesso che partire è una delle cose piu difficili quando ci si trova di fronte a questo Istanzio il viewmodel E verifico che il costruttore mi inizializzi la proprietà track
  27. Giusto per essere chiari Serve disciplina Quindi bisogna scriverei minimo codice per fare fallire il test
  28. Creo la proprietà
  29. E finalemente abbiamo la barra rossa
  30. Mi raccomando disciplina Bisgona scrivere il minimo codice per poter fare passare il test
  31. Inizializzo la proprietà
  32. Aggiungo un backfield all proprietà E rendo la proprietà in sola lettura
  33. Faccio riandare I test
  34. Ritorniamo alla storia da implementare Un altro test che mi viene in mente è Se schiaccio search il viewmodel deve recuperare la lista delle canzoni
  35. Penso che ci sia un servicio che si occuperà di fare la chiamata Rest con RestSharp emi restituirà I dati
  36. Per poter disaccoppiare l’implementazione di questo servizio dal viewmodel intriduco un interfaccia Stabilisce il contratto tra le due classi
  37. Arriviamo al test e leggiamolo E poi ve lo spiego in dettaglio
  38. Come visto prima ho introdotto un servizio che si occupa di reperire per me I dati via rest Per potermi concentrare sul viewmodel in realtà nel test non uso direttamente la mia implementazione del servizio Altrimenti test di integrazione ma non so se il test fallisce di chi è la colpa Per poter fare questo uso dei Mock
  39. Simulano il comportamento dell’oggetto che sostituiscono Di fatto implementano l’interfaccia dell’oggetto reale Possono essere più o meno stupidi
  40. Altro elemento nuovo e il comando che viene utilizzato dal tasto search - Definito come una proprietà
  41. Per fare questo ci appoggiamo all’interfaccia ICommand
  42. In realtà l’implementazione che utilizzo io è quella di Prism Dopo vi farò vedere come collegare la proprietà che abbiamo scritto prima con la proprietà command del button
  43. Quindi rieccoci al nostro test
  44. Per fare compilare dobbiamo aggiungere due proprietà al ViewModel
  45. Facciamo girare il test
  46. Implementiamo il comando ed effettuiamo la chiamata Proprio per il fatto che devo aggiungere il minimo codice che serve per passare il test nella OnSearch metto solo la chiamata al servizio
  47. Rendiamo in sola lettura il comando per il principio dell’incapsulation
  48. Altra storia visualizzare la lista Una volta ottenuti I dati dal servizio Vogliamo visualizzarli
  49. Istruiamo il mock per rispondere ad una chiamata ben definita Nello specifico a fronte di una chiamata con michelecapra Ritorna una lista con una canzone.
  50. Nella assert quindi veirifico che dopo la chiamata ci sia una canzone nella lista delle canzoni
  51. In questo caso per poter ottenere il test rosso Non devo fare nulla
  52. In questo caso per poter ottenere il test rosso Non devo fare nulla
  53. Per passarlo invece devo aggiornare il backfield track con il risultato della chiamata al servizio
  54. Per passarlo invece devo aggiornare il backfield track con il risultato della chiamata al servizio
  55. Altra storia cliccando sulla canzone voglio vedere il dettaglio
  56. Per poter navigare da una pagina all’altra abbiamo bisogno del NavigationService Ma come disaccoppiarlo dal nostro ViewModel?
  57. Bellisima implementazione già testata di Laurent Bugnion Per gestire la navigazione tra le pagine
  58. In questo caso viene aggiunta una dipendenza nuova del nostro oggetto
  59. A differenza del prcedente comando Passo la canzone con un id preciso
  60. In questa parte del viewmodel Non cambia nulla
  61. Per poter compilare dobbiamo aggiungere un nuovo parametro al costruttore
  62. Per poter compilare dobbiamo aggiungere un nuovo parametro al costruttore
  63. Per poter passare il test Teniamo il NavigationService da parte in una proprietà privata
  64. E implementiamo la chiamata effettiva
  65. Passiamo il test
  66. niente
  67. Rinomino il parametro passato a OnShowDetail da obj in track
  68. Rifaccio andare I test
  69. Si può fare anche del refactor sulle suite di test
  70. inizializzazione del viewmodel e e dei mock dei servizi si ripete
  71. Allora ho deciso di creare delle variabili private per la suite di test
  72. E di sfruttare un metodo messo a disposizione da Nunit Il Setup viene chiamato prima dell’esecuzione di ogni test
  73. Punto di contatto tra il viewmodel e la vista Infatti possiamo sfruttare la proprietà Datacontext per potere metter li il viewmodel
  74. In questo modo che è il più grezzo possiblie viene inizializzato il datacontext nella vista quando la si naviga
  75. Ssfruttiamo il binding delle proprietà per poter collegare le proprietà del viewmodel con gli oggetti sulla vista
  76. Lo stesso discorso viene fatto con la lista delle canzoni
  77. Lo stesso discorso viene fatto con la lista delle canzoni
  78. Lo stesso discorso viene fatto con la lista delle canzoni
  79. Lo stesso discorso viene fatto con la lista delle canzoni