Les résultats attendus d'un test d'unité sont-ils corrigés ou peuvent-ils dépendre des variables initialisées? Les résultats codés ou calculés augmentent-ils le risque d'introduire des erreurs dans le test de l'unité? Y a-t-il d'autres facteurs que je n'ai pas pris en compte?
Par exemple, lequel de ces deux est un format plus fiable?
[TestMethod]
public void GetPath_Hardcoded()
{
MyClass target = new MyClass("fields", "that later", "determine", "a folder");
string expected = "C:\\Output Folder\\fields\\that later\\determine\\a folder";
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
[TestMethod]
public void GetPath_Softcoded()
{
MyClass target = new MyClass("fields", "that later", "determine", "a folder");
string expected = "C:\\Output Folder\\" + string.Join("\\", target.Field1, target.Field2, target.Field3, target.Field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
Edit 1 : En réponse à la réponse de DXM, option 3 une solution préférée?
[TestMethod]
public void GetPath_Option3()
{
string field1 = "fields";
string field2 = "that later";
string field3 = "determine";
string field4 = "a folder";
MyClass target = new MyClass(field1, field2, field3, field4);
string expected = "C:\\Output Folder\\" + string.Join("\\", field1, field2, field3, field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
Je pense que la valeur attendue a été calculée dans les cas de test plus robustes et flexibles. En utilisant également de bons noms de variables dans l'expression qui calculent le résultat attendu, il est beaucoup plus clair que le résultat attendu est venu de la première place.
Cela dit, dans votre exemple spécifique, je ne ferais pas confiance à la méthode "codée soft", car elle utilise votre SUT (système sous test) comme entrée de vos calculs. S'il y a un bogue dans MyClass où les champs ne sont pas correctement stockés, votre test passera réellement parce que votre calcul de valeur attendue utilisera la mauvaise chaîne comme cible.gepath ().
Ma suggestion serait de calculer la valeur attendue où cela a du sens, mais assurez-vous que le calcul ne dépend de aucun code de la SUT elle-même.
En réponse à la mise à jour de l'OP à ma réponse :
Oui, sur la base de mes connaissances, mais une expérience quelque peu limitée dans la TDD, je choisirais l'option n ° 3.
Et si le code était comme suit:
MyTarget() // constructor
{
Field1 = Field2 = Field3 = Field4 = "";
}
Votre deuxième exemple n'aurait pas attrapé le bogue, mais le premier exemple.
En général, je recommanderais contre le codage logiciel car il peut cacher des bugs. Par exemple:
string expected = "C:\\Output Folder" + string.Join("\\", target.Field1, target.Field2, target.Field3, target.Field4);
Pouvez-vous repérer le problème? Vous ne feriez pas la même erreur dans une version codée dur. Il est plus difficile d'obtenir les calculs corrects que les valeurs codées dures. C'est pourquoi je préfère travailler avec des valeurs codées rigides que celles-ci.
Mais il y a des exceptions. Et si votre code doit exécuter Windows et Linux? Non seulement le chemin doit être différent, il doit utiliser différents séparateurs de chemins! Calculer le chemin à l'aide de fonctions qui résoutit la différence entre peut avoir un sens dans ce contexte.
À mon avis, vos deux suggestions sont moins qu'idéal. Le moyen idéal de le faire est celui-ci:
[TestMethod]
public void GetPath_Hardcoded()
{
const string f1 = "fields"; const string f2 = "that later";
const string f3 = "determine"; const string f4 = "a folder";
MyClass target = new MyClass( f1, f2, f3, f4 );
string expected = "C:\\Output Folder\\" + string.Join("\\", f1, f2, f3, f4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
En d'autres termes, le test doit fonctionner exclusivement sur la base de l'entrée et de la sortie de l'objet, et non basé sur l'état interne de l'objet. L'objet doit être traité comme une boîte noire. (Je ne regarde pas d'autres problèmes, comme l'inadéquation de l'utilisation de String.Join au lieu de path.combine, car ceci n'est qu'un exemple.)
Il y a beaucoup de concepts possibles, fait quelques exemples pour voir la différence
[TestMethod]
public void GetPath_Softcoded()
{
//Hardcoded since you want to see what you expect is most simple and clear
string expected = "C:\\Output Folder\\fields\\that later\\determine\\a folder";
//If this test should also use a mocked filesystem it might be that you want to use
//some base directory, which you could set in the setUp of your test class
//that is usefull if you you need to run the same test on different environments
string expected = this.outputPath + "fields\\that later\\determine\\a folder";
//another readable way could be interesting if you have difficult variables needed to test
string fields = "fields";
string thatLater = "that later";
string determine = "determine";
string aFolder = "a folder";
string expected = this.outputPath + fields + "\\" + thatLater + "\\" + determine + "\\" + aFolder;
MyClass target = new MyClass(fields, thatLater, determine, aFolder);
//in general testing with real words is not needed, so code could be shorter on that
//for testing difficult folder names you write a separate test anyway
string f1 = "f1";
string f2 = "f2";
string f3 = "f3";
string f4 = "f4";
string expected = this.outputPath + f1 + "\\" + f2 + "\\" + f3 + "\\" + f4;
MyClass target = new MyClass(f1, f2, f3, f4);
//so here we start to see a structure, it looks more like an array of fields
//so what would make testing more interesting with lots of variables is the use of a data provider
//the data provider will re-use your test with many different kinds of inputs. That will reduce the amount of duplication of code for testing
//http://msdn.Microsoft.com/en-us/library/ms182527.aspx
The part where you compare already seems correct
MyClass target = new MyClass(fields, thatLater, determine, aFolder);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
Pour résumer: En général, votre premier essai codé en dur fait le plus de sens pour moi, car il est simple, tout droit au point, etc. Si vous commencez à obtenir un chemin d'accès à un chemin trop élevé, mettez-le dans la méthode de configuration.
Pour plus de futurs tests structurés, je voudrais vérifier les données de données afin que vous puissiez simplement ajouter plus de lignes de données si vous avez besoin de plus de situations de test.
Les cadres de test modernes vous permettent de fournir des paramètres à votre méthode. J'utiliserais ceux:
[TestCase("fields", "that later", "determine", "a folder", @"C:\Output Folder\fields\that later\determine\a folder")]
public void GetPathShouldReturnFullDirectoryPathBasedOnItsFields(
string field1, string field2, string field3, string field,
string expected)
{
MyClass target = new MyClass(field1, field2, field3, field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
Cela présente plusieurs avantages, à mon avis: