Deuxième livraison

Nous sommes toujours dans la grande saga de l'été sur la conception émergente. Après l'intégration d'un second scénario, notre deuxième version du logiciel est sur le point d'être terminée.
Allons-nous y parvenir aujourd'hui ?

Un des avantages du développement en intégration continue est la capacité à disposer à tout instant d'un logiciel exécutable.
En l'occurrence, même si la réalisation du deuxième scénario n'est pas terminée, nous pouvons toujours exécuter l'application et bénéficier du fonctionnement du 1er scénario.
Si l'on essaie de dérouler le 2ème en sélectionnant un élément, il ne se passe rien -- on pouvait s'y attendre.

La finalisation de notre 2ème version se passe à 2 niveaux. La connexion de notre logique applicative avec

  1. l'interface utilisateur
  2. le composant en charge de l'audio

Pour le 1er point, nous avions précédemment décidé que des tests unitaires automatisés étaient superflus. Je crois qu'ils le sont encore.
Je ne vais pas m'étendre sur cette partie de code qui tient sur très peu de lignes. Sa complexité réside surtout dans une bonne connaissance WinForms (que je suis très loin d'avoir) pour utiliser les méthodes et évènements adéquats de chaque widget.

Pour le 2ème point, il s'agit désormais de remplacer le mock que nous avions mis en place par un composant qui implémente IAudioPlayer.
Cependant, envisager un test unitaire automatisé pour ce composant est un peu hasardeux : seul un humain pourra contrôler que le morceau joué est bien celui demandé lors d'un appel à Play.
Pour ce genre de composant, il est plus raisonnable d'utiliser une méthode de test unitaire encore très courante : un exécutable dédié avec un bouton pour déclencher l'appel à la méthode concernée :

public partial class MainForm : Form
{
  IAudioPlayer player_;

  public MainForm()
  {
    //...
    player_ = new AudioPlayer();
  }

  void PlayButtonClick(object sender, EventArgs e)
  {
    player_.Play(this.UrlBox.Text);
  }
}

Pour implémenter cette fonctionnalité, nous allons au plus simple en utilisant une intégration minimaliste de DirectShow :

public class AudioPlayer : IAudioPlayer
{
  FilgraphManager manager_;

  public AudioPlayer() {}

  void IAudioPlayer.Play(string audioUrl)
  {
    manager_ = new FilgraphManagerClass();
    manager_.RenderFile(audioUrl);
    manager_.Run();
  }
}

Avec notre exécutable dédié, nous constatons que le test unitaire AudioPlayerréussit (la reproduction audio fonctionne) mais dès que l'on tente de reproduire consécutivement 2 morceaux, la reproduction devient une cacophonie. En effet, alors que le 2ème morceau démarre, le premier morceau ne s'arrête pas pour autant. Il faut donc explicitement provoquer l'arrêt :

void IAudioPlayer.Play(string audioUrl)
{
  manager_.Stop();
  manager_ = new FilgraphManagerClass();
  manager_.RenderFile(audioUrl);
  manager_.Run();
}

Le test unitaire étant satisfaisant, l'intégration est immédiate en substituant dans le programme principal l'AudioPlayer à notre mock temporaire :

public MainForm()
{
  //...
  subscription_ = new PodcastSubscription(TheSubscriptionView,new XmlFetcher(),new AudioPlayer());
}

Nous pouvons livrer le logiciel et enchainer, dans le prochain épisode, avec l'implémentation d'un nouveau scénario.
Comme d'habitude, le projet complet est disponible en annexe de ce billet.

Qu'avons nous constaté aujourd'hui ?

  • Que le TDD n'est pas le seul moyen "autorisé" pour faire des tests unitaires. Dans certains cas, une autre approche est mieux adaptée sans remettre en cause nos principes de développement.
  • Que lorsque l'on se trouve dans un état sain avec des composants implémentés progressivement et bien testés dans leurs interactions avec des interfaces cohérentes, l'intégration continue est une activité où l'on ne rencontre que peu d'embuches.
1. Le 18 septembre 2007, 11:48 par scrum-france.net

Communauté : Septembre 2007

A l'occasion du lancement de la coupe du monde de rugby, Claude Aubry nous rappelle les valeurs communes de Scrum avec ce sport d'équipe. Restons ouverts grâce à jc-QualityStreet qui suit de près les relations entre Scrum et CMMI. Suite de la......