原理模块去:Écriture de tests unitaires avec作证

MISE À JOUR: À computer du 1er mai 2021, le dépôt central GoCenter a été mis hors service et toutes fonctionnalités seront obsolètes。倒上美味佳肴,再来点美味佳肴,各位la博客文章dépréciation
chque mois, GoCenter décerne aux modules les plus performants un金花鼠徽章Qui reconnaît leur réussite。文章中提到了quelque -uns de ces更好的模块et leur utilization dans Go。
我们的思想développeurs我们的思想,même我们的思想structurés:我们的思想suggèrent我们的思想,我们的思想,我们的思想。Ces avertissement nous rendent timides, car nous crignons de caser quelque chose。这些应用程序是变革者,'améliorer和创新者。
这是我们的cela que les tests unitaires sont une party inentielle du développement de logiciels。我的助手développeurs à déterminer我的小律师,律师,律师,律师,律师,律师prévue。Avec la quantité adaptée de couverture de tests unitaires en place, les développeurs se sentent + en confifipour modifier leurs implémentations, et même la réusiner à partir de zéro。Ils savent en effet qu ' l Ils peuvent便利vérifier si la nouvelle版本功能提供时间prévu。
重要的是统一的测试和完整的集合même语言扩充parallèlement à la complexité des logiciels。我们的测试代码是如何使我们的国家变得更加美好être我们的环境,我们的环境是être我们的环境是怎样的à我们的产品是怎样的développeurs à我们的利益是怎样的à我们的利益是怎样的。
Pour nos projets de communauté Go tell que GoCenter, nous utilisons beaucoup le module作证,非常apprecie。Il fournit un ensemble de packages Golang pour réaliser des function de test unitaire essentielles。
我们的文章,你的意见,你的利益,利用原则fonctionnalités你的证词,écrire你的测试,你的工作,便利à lire et à维护。您的密码à您的测试是统一的,使用是独特的,découvrirez您的证物是统一的,您的证物是统一的tâche effectuée,代码是résultant après我们的证物是统一的。这是我们在蒙特利尔市所能办到的事。
作证:Un«顶级地鼠»
作证Est UN套装de包欢乐倒les développeurs。Il possède + de 11000 étoiles sur GitHub et bénéficie d 'un优秀的支持社区。作证étend勒干部德测试léger de Go pour effectuer des断言et des dépendances虚构。
ce fonctionnalités, en + de la conconfant quotidienne de notre équipe communautaire去吧,一个伟大的聚会pourquoi le module证明自己重新开始了«Top Gopher»dans GoCenter.Si vous consultez les métadonnées complètes de GoCenter sur le module作证,Vous comprendrez pourquoi:
- 文件自述Du module vous dirige vers une文档complète。头脑清醒,头脑清醒,再加上"模块代码l 'onglet GoDoc,Qui affiche la文档générée自动功能等加返场。
- Les这里所使用的等指标de GoCenterMontrent que ce module est très apprécié et可实现的,avec de nombreux téléchargements, fork, contributeurs et utilements par d ' aures模块去.

- L '这里的安全de GoCenter révèle également que la版本actuelle de ce module et ses dépendances ne présentent pas de vulnérabilité NVD connue, comme le confirme une分析approfondie JFrog x射线.

Une Unité GoLang Simple
Pour commencer à écrire les tests unitaires, nous avons tout d'abord besoin d 'un composition à tester。Pour cet exercise, nous allons utiliser la définition de service suivante:
type hth华体会最新官方网站ProductService接口{IsProductReservable(id int) (bool, error)}
Pour cette définition de service, nous avons une implémentation que nous souhaitons tester。L 'implémentation obéit à une logique métier pour déterminer si un product est réservable ou non。L 'implémentation s'appuie également sur un composant Objet d 'accès aux données提供有关产品的信息。L 'implémentation doit réussir les cas de test simplifiés suivants:
- L 'implémentation服务doit respecter la définition服务
- Les products ajoutés au catalog il y + de 1 sont réservables
- Les autres产品ne sont pas réservables
- 我们的产品是不可磨灭的,不可磨灭的
L 'implémentation du service ressemble à ce qui suit:
类型Prohth华体会最新官方网站ductServiceImpl结构{productDAO坚持。ProductDAO} //构造函数func NewProductSerhth华体会最新官方网站viceImpl(dao persist.ProductDAO) *ProductServiceImpl {return &ProductServiceImpl{ProductDAO: dao,}} func (s *ProductServiceImpl) IsProductReservable(id int) (bool, error){//从数据库product中获取产品信息,err:= s. ProductDAO . getproduct (id)如果err != nil{返回false, fmt. intl。如果product == nil{返回false, fmt. error ("failed to get product details: %w", err)}Errorf("product not found for id %v", id)} //只有在1年前添hth华体会最新官方网站加到目录中的产品才可以保留返回product. createdat . before (time.Now()。AddDate(-1, 0,0)), nil}
利用de作证
维护人员知道如何处理服务简单,知道如何使用工具,证明倒créer唯一的测试是如何做的prévu。
执行d 'Assertions
Les tâches Les + élémentaires effectuées par Les tests unitaires sont des断言。断言具有渗透性généralement de vérifier si Les actions effectuées par le test à l 'aide d 'une entrée déterminée produisent la sortie attendue。Elles peuvent également être utilisées pour vérifier si les composents suivent les règles de concept souhaitées。
En utilisant Go unique pour exécuter les断言nécessaires pour vérifier si le premier cas de test est respecté et si notre implémentation de service est initialisée correctement, nous obtenons le code suant:
import ("service" "testing") func TestNewPrhth华体会最新官方网站oductServiceImpl(t *testing. t) {productDaoMock:= productDaoMock{} //忽略le mock pour l'instant productServiceImpl:= NewProductServiceImpl(&productDaoMock) //断言productServiceImpl实现ProductService。否则将破坏编译器。var _服务。hth华体会最新官方网站如果productServiceImpl == nil {t.Fatal("Product Service not initialized")},则productServiceImpl = productServiceImpl。productDAO == nil {t.Fatal("产品服务依赖关系未初始化")}}
倒助手的断言,作证的包装github.com/stretchr/testify/assert.Ce包possède plusieurs méthodes qui peuvent aider à比较商les valeurs par rapport aux résultats attendus。Si nous remplaçons nos comparison par ces méthodes, nous obtenons le résultat suivant:
import (" github.com/stretchr/testify/assert" "service" "testing") func TestNewPhth华体会最新官方网站roductServiceImpl(t *testing. t){断言:= assert.New(t) productDaoMock:= productDaoMock {} // Ignorer le mock pour l'instant productServiceImpl:= NewProductServiceImpl(&productDaoMock) if !NotNil(hth华体会最新官方网站productServiceImpl, "产品服务未初始化"){t.Fatal("产品服务未初始化")}if !productDAO, "产品服务依赖项未初始化"){t.Fatal("产品服务依赖项未初始化")}}
En plus d 'aider avec les断言,les包作证fournissent également une meilleure信息lorsque l 'une de ces opérations échoue。例如,si nous avons oublié de définir le champ productDAO dans le constructeur d 'implémentation de service, nous obtenons l ' échec de test suivant:
===执行TestNewProhth华体会最新官方网站ductServiceImpl TestNewProductServiceImpl: product_service_impl_test。go:22: Error Trace: product_service_impl_test。错误:期望值不是nil。测试:TestNewProhth华体会最新官方网站ductServiceImpl消息:产品服务依赖关系未初始化TestNewProductServiceImpl: product_service_impl_test。go:23:产品服务依赖未初始化——FAIL: TestNewProductServiceImpl (0.00s)hth华体会最新官方网站
Jusqu ' à présent, même si nous disposons d ' une meilleure information et de méthodes + pratiques pour exécuter les断言,nous nepouvions pas réduire la taille de notre test。Nous avons toujours un modèle répétitif if-not-assertion-break, qui peut rendre + difficile la lecture de notre code de test。证明包倒便利点github.com/stretchr/testify/require.Ce包possède les mêmes méthodes d 'assertion fournies par le package d 'assertion, mais il interrompt le test immédiatement lorsqu 'une assertion échoue。En introduction ce package, nous obtenons le code de test suant, plus court et plus easy à lire:
import ("github.com/stretchr/testify/require" "service" "testing") func TestNewPrhth华体会最新官方网站oductServiceImpl(t *testing. t){断言:= require.New(t) productDaoMock:= productDaoMock {} // Ignorer le mock pour l'instant productServiceImpl:= NewProductServiceImpl(&productDaoMock)断言。implements ((*service. productservice)(nil), new(productServiceImpl), "产品服务实现不支持服务定义")断言。NotNil(hth华体会最新官方网站productServiceImpl,“产品服务未初始化”)断言。"产品服务依赖关系未初始化")}
嘲笑de依赖性
Lors du test d 'un composons, nous devons idéalement l 'isoler complètement pour éviter d 'avoir des échecs ailleurs qui compromettraient nos tests。Cela est particulièrement难辨难辨的主合成物是什么意思的合成物测试仪dépendances由主合成物代理différentesDans le scénario que nous utilisons ici, notre implémentation de service repose sur un composant de la couche DAO(数据访问对象,对象'accès aux données)为产品提供accéder aux信息。
倾隔离之泉souhaitée,世界上最伟大的国家développeurs écrivent de fausses implémentations simplifiées de ces dépendances, à利用吊坠的试验。Ces fausses implémentations sont nommées嘲弄。
Nous pouvons créer une implémentation fiction du ProductDAO à injector dans l 'implémentation du service pour l 'exécution du test。L 'interface ProductDAO que notre mock doit implémenter ressemble à ce qui suit:
类型ProductDAO接口{GetProduct(id int)(*模型。产品,错误)}
Pour permettre l 'exécution du test, il est nécessaire que le mock fournisse行为兼容,这是一种必然的结果,这是一种必然的结果。我是说,我是说,我是说,我是说,我是说。En utilisant Go unique, notre cas de test avec le ressemblerait à ce qui suit:
import ("errors" "model" "persist" "testing" "time") type ProductDaoMock struct {} func (m *ProductDaoMock) GetProduct(id int)(*模型。产品,错误){开关id {case 1:返回&模型。产品{Id: 1,描述:" 2年前创建的产品",CreatedAt: time.Now()。AddDate(- 2,0,0),}, nil情况2:返回&模型。Product{Id: 2,描述:"最近创建的产品",CreatedAt: time.Now(),}, nil情况999:返回nil,坚持。ErrProductNotFound} return nil, nil} func testprhth华体会最新官方网站oductserviceimpl_isproducttreservable (t *testing.T) {testDataSet:= map[int]bool {1: true, 2: false,} productDaoMock:= productDaoMock {} productServiceImpl:= NewProductServiceImpl(&productDaoMock) for productId, expectedResult:= range testDataSet {reserved, err:= productServiceImpl. isproducttreservable (productId) if err != nil {t. fatalf ("Failed to check if product %v is reserved: "%s", productId, err)} if reservable != expectedResult {t.f alf("为产品id %v获得错误的可保留信息。预期:% v。get: %v", productId, expectedResult, reservable)}}} func TestProhth华体会最新官方网站ductServiceImpl_IsProductReservable_NotFound(t *testing.T) {productDaoMock:= productDaoMock {} productServiceImpl:= NewProductServiceImpl(&productDaoMock) _, err:= productServiceImpl. isproductreservable (999) if !errors。Is(err, persist.ErrProductNotFound) {t.Fatalf("获得意外错误结果:%s", err)}}
我们的校长problème我们的校长,我们的校长,我们的校长,我们的校长,我们的校长désormais distribuée。Une party de cellle -ci est implémentée dans le cas de test lui-même, où nous使者des événements au composant testé et exécutons des断言avec les résultats。L 'autre party est implémentée dans le mock,这是一种行为兼容的测试réalisés par le cas de test。这是最容易的评论,这是一个测试的过程,没有理由的事情problème dans le test lui-même,这是一个可以做的事情,一个可以做的事情données需要。
Un autre problème qui peut le renre encore加上最令人沮丧的部分également le mock entre plusieurs cas de test。最可能的修改appliquées au mock pour qu'il满足于测试和询问。Dans notre scénario, seuls 3 cas de test qunous intéressent, mais vous pouvez imaginer à quel point cela pourrait devenir compliqué si nous avions de cas de test plus complex。除名le mock en plusieurs mock ne serait pas non + forcément实用,et pourrait潜能恶化la情况en répandant encore davantage la complexité。De +, si notre接口虚构的变化,nous devons mettre à jour plusieurs模仿倒qu' ililrestent兼容。
实验的逻辑学知识centralisée和indépendante。证明包倒便利点github.com/stretchr/testify/mock.这是一个包,它的外面倒créer模仿的渗透,注入的行为,'exécution,这是一个测试,这是公平的。我的逻辑是虚构的,我的逻辑是测试的。
En utilisant le package fictif作证pour créer notre mock DAO et En déplaçant l 'initialisation du comement fictif vers les cas de test, ainsi qu 'en ajoutant le package作证requis pour exécuter nos断言,notre code de test ressemble à ce qui suit:
import ("github.com/stretchr/testify/require" "github.com/stretchr/testify/mock" "errors" "model" "persist" "testing" "time") type productdaotestfymock结构{mock。func (m * productdaotestfymock) GetProduct(id int)(*模型。Product, error) {args:= m.c called (id) return args. get (0).(*model.Product), args. error (1)} func hth华体会最新官方网站TestProductServiceImpl_IsProductReservable(t *testing.T){断言:= require.New(t) //注册测试模拟productDaoMock:= productdaotestfymock {} productDaoMock. test (t)(“GetProduct”,1).Return(模型。产品{Id: 1,描述:" 2年前创建的产品",CreatedAt: time.Now()。AddDate(-2, 0,0),}, nil)(“GetProduct”,2).Return(模型。Product{Id: 2,描述:"最近创建的产品",CreatedAt: time.Now(),}, nil) testDataSet:= map[int]bool {1: true, 2: false,} productServiceImpl:= NewProductSerhth华体会最新官方网站viceImpl(&productDaoMock) for productId, expectedResult:= range testDataSet {reserved, err:= productServiceImpl. isproductreservable (productId)断言。NoErrorf(err,"Failed to check if product %v is reserved: %s", productId, err)断言。Equalf(expectedResult, reservable,"Got wrong reservable info for product id %v", productId)}} func TestPrhth华体会最新官方网站oductServiceImpl_IsProductReservable_NotFound(t *testing.T){断言:= require.New(t) //注册测试模拟productDaoMock:= productDaoMock {} productDaoMock。On("GetProduct", 1). return ((*model.Product)(nil), persistent . errproductnothth华体会最新官方网站found) productServiceImpl:= NewProductServiceImpl(&productDaoMock) _, err:= productServiceImpl. isproductreservable (1) if !errors。Is(err, persist.ErrProductNotFound){断言。Failf("Got unexpected error result", "Got unexpected error result: %s", err)}}
我'implémentation我的想法,我的行为,我的想法,我的想法,我的想法,我的想法,我的想法,我的想法,我的想法,我的想法。Notez également评论le行为fictif enregistré最排除的au cas de test où il est placé,汽车il明显的à une instance虚构的唯一的qui n 'est pas partagée entre plusieurs测试。Les tests enregistrent même des comportements différents pour l 'ID de product 1 sans aucun problème。productdaotestfymock peut être réutilisé en toute sécurité entre plusieurs cas de test, car il n 'a aucun comment。
结论
J 'espère que vous avez trouvé de de meilleurs测试unitaires dans vos项目。Pour ajouter见证à votre项目à l 'aide des modules Go et commencer à vous amuser avec, exécutez simplement les commands suivantes:
美元出口GOPROXY = https://gocenter。IO $去得到github.com/stretchr/testify
在GoCenter上作证ou faites des reches pour découvrir encore plus de modules Go très intéressants。

