Partagez le deuxième chapitre, sur l'essai de conduite. Les tests ici sont principalement destinés aux tests back-end Web : pourquoi vous devriez écrire des cas de test (c'est-à-dire si l'amélioration des cas de test est une perte de temps), comment améliorer vos cas de test, comment la conception du code peut simplifier l'écriture des cas de test. , et quelques idées ultérieures .
1. Pourquoi devriez-vous rédiger des cas de test
Cette habitude est généralement considérée comme un comportement qui retarde la progression du développement. Vous devez passer presque le même temps à développer votre code pour améliorer progressivement vos cas de test. Cependant, pendant le processus de développement, après avoir développé un morceau de code, si vous êtes responsable et ne laissez pas le problème au testeur le trouver, vous effectuerez généralement des tests manuels à ce moment-là. Par exemple :
Exécutez certaines méthodes dans le code pour voir si la valeur de sortie est comme prévu.
Modifiez la base de données/le cache, puis exécutez certaines méthodes pour voir si les modifications de la base de données sont comme prévu.
Utilisez des outils pour simuler la demande de certaines interfaces afin de voir si la valeur de retour de l'interface/la valeur modifiée dans la base de données répond aux attentes.
S'il existe une page frontale, cela impliquera également un débogage conjoint front-end et back-end, c'est-à-dire, via une interaction frontale sur la page frontale, vérifier si les commentaires front-end répondent aux attentes pour vérifier indirectement l'exactitude du code back-end.
Les outils de test modernes font de leur mieux pour résumer ces comportements de test manuel dans des blocs de code. Lorsque vous effectuez consciemment des tests manuels, vous avez réellement commencé à essayer le comportement du scénario de test. Puisque les tests peuvent être effectués manuellement, pourquoi avez-vous besoin d’utiliser du code pour implémenter les tests ?
Le code peut être réutilisé ou peut réaliser plus de fonctions après une simple refactorisation, mais lorsque vous choisissez de le faire manuellement, vous devez recommencer à chaque fois.
Un flux de travail mature doit inclure un processus de révision du code. Il existe de nombreuses façons de lire votre code phrase par phrase, ou de vérifier l'intégralité et l'exactitude de votre code de test, puis d'exécuter vos cas de test. Ce dernier est plus simple.
Lorsque le code est modifié, par exemple pour corriger un bug, il est difficile de garantir si vos modifications affecteront d'autres parties qui dépendent de votre code. À l'ère des tests manuels, il existe ce qu'on appelle les tests de régression, qui consistent à retester votre système après avoir corrigé le bogue. Mais si vous disposez déjà d’un scénario de test complet, exécutez simplement la commande directement.
Lorsque vous refactorisez votre code, idem.
2. Comment améliorer vos cas de test
Avant d'entrer dans la phase de raffinement, parlez d'abord de la façon dont vous allez mettre en œuvre le scénario de test.
describe Meme do before do @meme = Meme.new end describe "when asked about cheeseburgers" do it "must respond positively" do @meme.i_can_has_cheezburger?.must_equal "OHAI!" end end describe "when asked about blending possibilities" do it "won't say no" do @meme.will_it_blend?.wont_match /^no/i end end end
Le code ci-dessus provient du minitest de Ruby. Le bloc de code contenu avant correspond à ce qui doit être fait avant d'exécuter le scénario de test suivant. Il prend généralement également en charge une méthode correspondante à exécuter après l'exécution du scénario de test. Quelques petits jugements sont faits dans chaque cas d'utilisation.
Le premier paragraphe mentionnait certains contenus de tests qui sont souvent impliqués dans les tests manuels. En voici 2 et 3 pour explication. Lorsque vous effectuez des tests liés à la base de données, vous devez insérer une partie des données de test avant et supprimer les données de test après. Dans le scénario de test intermédiaire, l'exactitude du code est confirmée en exécutant la méthode correspondante. Une fois l'exécution terminée : vérifiez les modifications de données/vérifiez s'il y a des exceptions attendues/si les résultats attendus sont renvoyés. S'il s'agit d'une interface, il s'agit de lancer la requête correspondante via le code, puis de vérifier si le contenu renvoyé renvoie les résultats attendus. Si nécessaire, vérifiez si les données de la base de données répondent aux modifications attendues.
Vous avez maintenant un cas de test, mais il reste encore un cas particulier à considérer. J'ai maintenant écrit un scénario de test relativement complet pour une fonction. Après l'avoir exécuté, j'ai réussi le test, mais j'ai constaté qu'il y avait encore des erreurs pour cette fonction dans les journaux en ligne. Après vérification, j'ai découvert qu'une certaine branche de la fonction n'avait pas été testée lors du test précédent. Il est arrivé que quelque chose en ligne s'exécute sur cette branche. En conséquence, une erreur de syntaxe très obscure a été signalée. que tous les codes sont corrects ? Ce qui doit être introduit ici est un concept appelé couverture des cas de test. Fondamentalement, chaque langage aura une implémentation correspondante. Grâce à la couverture des cas de test, nous pouvons vous dire quantitativement si votre cas de test a exécuté tout le code d'un certain fichier. Ce que vous devez faire est de vous assurer que votre couverture reste à 100 % autant que possible.
Dans un sens, les cas de test et la couverture des tests sont des outils utilisés pour accroître la confiance des développeurs dans leur propre code. Cependant, ils ne sont pas omnipotents. Il est toujours possible que certains paramètres manquent dans les cas de test. Bien entendu, votre code n'a pas été écrit pour cette possibilité. En fin de compte, la couverture du cas de test ne peut vous indiquer que le code que vous avez écrit. . Je l’ai testé, mais vous ne pouvez rien faire contre cette possibilité que vous n’ayez pas envisagée. Par conséquent, écrivez autant que possible du code strict. Par exemple, utilisez autant que possible === au lieu de == en JavaScript, utilisez des normes de programmation de type fort, etc., pour réduire les risques potentiels liés à l'acceptation d'un paramètre trop grand. gamme.
3. Comment la conception du code simplifie l'écriture des cas de test
L'ensemble du Web (sans s'y limiter) comprend généralement trois niveaux de code : le traitement et les calculs de données purs, impliquant des bases de données et impliquant des protocoles réseau spécifiques. Parmi elles, les opérations de données pures sont principalement des fonctions ou d'autres codes qui traitent des opérations ordinaires. Lorsqu'il s'agit de bases de données, il s'agit du M dans MVC au sens traditionnel. Lorsqu'il s'agit de protocoles réseau spécifiques, il s'agit du C correspondant. Ces trois tests correspondent aux trois premiers éléments du contenu régulier des tests de la première section.
Étant donné que le niveau C implique généralement le rendu des pages et la simulation des protocoles correspondants, concentrer généralement le test sur les fonctions et les codes liés à la base de données peut réduire la complexité du code du scénario de test, qui nécessite le moins possible le code du contrôleur. . Quelques recommandations actuelles pour des applications plus complexes :
Placez la vérification de base des données dans la couche M. S'ils sont développés avec Ruby, ActiveRecord et Mongoid fournissent tous deux des fonctions de validation très pratiques.
Essayez d'utiliser le mode Pub/Sub dans le code avec quelques hooks fournis dans l'ORM pour établir la communication entre les modèles. Par exemple, lorsque A publie un message lors de sa création, B modifie une de ses propres valeurs d'attribut après avoir écouté le message.
Utilisez le mode Commande pour extraire certaines fonctions non commerciales du système, telles que l'envoi d'e-mails.
Référence pour les suggestions ci-dessus : Laravel wisper resque
4. Idée
Le contenu ci-dessus évite les cas de test qui nécessitent un débogage conjoint du front-end et du back-end. Le contenu suivant est principalement axé sur ce domaine. Ruby a déjà quelques implémentations élégantes dans ce sens. Si vous êtes intéressé, vous pouvez d'abord vous adresser directement à Capybara.
Avec la popularité d'une série de pilotes de navigateur, notamment Selenium Phantomjs et Watir basés sur le premier, contrôler le navigateur à l'aide de code n'est plus une affaire compliquée. Sur la base de cette fonctionnalité, vous pouvez essayer de diviser les tests front-end en quatre étapes :
等待某标志性元素出现(例如等待页面载入玩,或者某个内容异步加载出现)
模拟用户操作,这里的操作包括且不局限于用户点击、用户输入
等待反馈中标志性元素出现(例如某某输入框出现)
判断内容,是否符合预期
基于这个流程,可以解决绝大多数的前端测试。但是单纯依靠这个流程任然不够,因为页面中可能出现例如验证码这样的阻碍元素,在不修改代码的前提下,可以尝试通过数据库/缓存来取到这些内容。同样,和测试接口相同,这里也涉及到在测试前数据库中插入测试数据,测试用例执行后严重数据库里面数据变化,以及全部测试完毕后删除测试数据的内容。最终导致这块测试用例代码的实现需要同时对前端后端有一定的了解。目前还在考虑在借鉴 Capybara 的基础上,设计出更加通用的方案。
最后贴一段 Capybara 的代码结束这段内容:
feature "Signing in" do background do User.make(:email => 'user@example.com', :password => 'caplin') end scenario "Signing in with correct credentials" do visit '/sessions/new' within("#session") do fill_in 'Email', :with => 'user@example.com' fill_in 'Password', :with => 'caplin' end click_button 'Sign in' expect(page).to have_content 'Success' end given(:other_user) { User.make(:email => 'other@example.com', :password => 'rous') } scenario "Signing in as another user" do visit '/sessions/new' within("#session") do fill_in 'Email', :with => other_user.email fill_in 'Password', :with => other_user.password end click_button 'Sign in' expect(page).to have_content 'Invalid email or password' end end