估計很多前端都沒學過單元測試~

大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以加我微信?ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。已進行四個月了,很多小伙伴表示收獲頗豐。

想學源碼,極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。同時推薦參與源碼共讀活動。


前言

對于現在的前端工程,一個標準完整的項目,通常情況單元測試是非常必要的。但很多時候我們只是完成了項目而忽略了項目測試。我認為其中一個很大的原因是很多人對單元測試認知不夠,因此我寫了這邊文章,一方面期望通過這篇文章讓你對單元測試有一個初步認識。另一個方面希望通過代碼示例,讓你掌握寫單元測試實踐能力。

前端為什么需要單元測試?

  1. 必要性:JavaScript 缺少類型檢查,編譯期間無法定位到錯誤,單元測試可以幫助你測試多種異常情況。

  2. 正確性:測試可以驗證代碼的正確性,在上線前做到心里有底。

  3. 自動化:通過 console 雖然可以打印出內部信息,但是這是一次性的事情,下次測試還需要從頭來過,效率不能得到保證。通過編寫測試用例,可以做到一次編寫,多次運行。

  4. 保證重構:互聯網行業產品迭代速度很快,迭代后必然存在代碼重構的過程,那怎么才能保證重構后代碼的質量呢?有測試用例做后盾,就可以大膽的進行重構。

現狀

下面是一份抽樣調查片段,抽樣依據如下:

  • 向 200 名相關者發出在線問卷調查,其中 70 人回答了問卷中的問題,前端人數占 81.16%,如果你有興趣的話,也可以幫我填一下調查問卷 (https://www.wjx.cn/vm/Ombu9q1.aspx)

  • 數據收集日期:2021.09.21—2021.10.08

  • 目標群體:所有開發人員

  • 組織規模:不到 50 人,50 到 100人, 100人以上

你執行過 JavaScript 單元測試嗎?

4a6a061fd013a913d4c276e67ed1f384.png

調查中的另一個有趣的見解是,在大型組織中單元測試更受歡迎。其中一個原因可能是,由于大型組織需要處理大規模的產品,以及頻繁的功能迭代吧。這種持續的迭代方式,迫使他們進行自動化測試的投入。更具體地說,單元測試有助于增強產品的整體質量。

a5f7538c885fd8ef930511d0a43ddeda.png

另外,報告顯示超 80% 人認為單元測試可以有效的提高質量,超 60% 人使用過 Jest 去編寫前端單元測試,超 40% 的人認為單元測試覆蓋率是重要的且覆蓋率應該大于 80%。

常見單元測試工具

目前用的最多的前端單元測試框架主要有 Mocha (https://mochajs.cn/)、Jest (https://www.jestjs.cn/),但我推薦你使用 Jest,因為 Jest 和 Mocha 相比,無論從 github starts & issues 量,npm下載量相比,都有明顯優勢。

github stars 以及 npm 下載量的實時數據,參見:jest vs mocha (https://www.npmtrends.com/jest-vs-mocha) 截圖日期為 2021.11.25

Github stars & issues

745b5cafd715a6d067b66c53826b163c.png

npm 下載量

Jest 的下載量較大,一部分原因是因為 create-react-app 腳手架默認內置了 Jest, 而大部分 react 項目都是用它生成的。

90eb2abd65d687834a5b100b047ca9de.png

從 github starts & issues 以及 npm 下載量角度來看,Jest 的關注度更高,社區也更活躍

框架對比

框架斷言異步代碼覆蓋率
Mocha不支持(需要其他庫支持)友好不支持(需要其他庫支持)
Jest默認支持友好支持
  • Mocha 生態好,但是需要較多的配置來實現高擴展性

  • Jest 開箱即用

比如對 sum 函數寫用例

./sum.js

function?sum(a,?b)?{return?a?+?b;
}module.exports?=?sum;

Mocha + Chai 方式

Mocha 需要引入 chai 或則其他斷言庫去斷言, 如果你需要查看覆蓋率報告你還需要安裝 nyc 或者其他覆蓋率工具

./test/sum.test.js

const?{?expect,?assert?}?=?require('chai');
const?sum?=?require('../sum');describe('sum',?function()?{it('adds?1?+?2?to?equal?3',?()?=>?{assert(sum(1,?2)?===?3);});
});

Jest 方式

Jest 默認支持斷言,同時默認支持覆蓋率測試

./test/sum.test.js

const?sum?=?require('./sum');describe('sum?function?test',?()?=>?{it('sum(1,?2)?===?3',?()?=>?{expect(sum(1,?2)).toBe(3);});//?這里?test?和?it?沒有明顯區別,it?是指:?it?should?xxx,?test?是指?test?xxxtest('sum(1,?2)?===?3',?()?=>?{expect(sum(1,?2)).toBe(3);});
})

可見無論是受歡迎度和寫法上,Jest 都有很大的優勢,因此推薦你使用開箱即用的 Jest

如何開始?

1.安裝依賴

npm?install?--save-dev?jest

2.簡單的例子

首先,創建一個 sum.js 文件

./sum.js

function?sum(a,?b)?{return?a?+?b;
}module.exports?=?sum;

創建一個名為 sum.test.js 的文件,這個文件包含了實際測試內容:

./test/sum.test.js

const?sum?=?require('../sum');test('adds?1?+?2?to?equal?3',?()?=>?{expect(sum(1,?2)).toBe(3);
});

將下面的配置部分添加到你的 package.json 里面

{"scripts":?{"test":?"jest"},
}

運行 npm run test ,jest 將打印下面這個消息

a1a7c92bc6420467e6c3ea0f01c8b8aa.png

3.不支持部分 ES6 語法

nodejs 采用的是 CommonJS 的模塊化規范,使用 require 引入模塊;而 import 是 ES6 的模塊化規范關鍵字。想要使用 import,必須引入 babel 轉義支持,通過 babel 進行編譯,使其變成 node 的模塊化代碼

如以下文件改寫成 ES6 寫法后,運行 npm run test將會報錯

./sum.js

export?function?sum(a,?b)?{return?a?+?b;
}

./test/sum.test.js

import?{?sum?}?from?'../sum';test('adds?1?+?2?to?equal?3',?()?=>?{expect(sum(1,?2)).toBe(3);
});

報錯

09e33b093e5a6da51a6a7a6e1e9cea7a.png

為了能使用這些新特性,我們就需要使用 babel 把 ES6 轉成 ES5 語法

解決辦法

安裝依賴

npm?install?--save-dev?@babel/core?@babel/preset-env

根目錄加入.babelrc

{???"presets":?["@babel/preset-env"]?}

再次運行 npm run test ,問題解決

ddc43706ec034bd2c9cf763b975194b7.png

原理

jest 運行時內部先執行( jest-babel ),檢測是否安裝 babel-core,然后取 .babelrc 中的配置運行測試之前結合 babel 先把測試用例代碼轉換一遍然后再進行測試

4.測試 ts 文件

jest 需要借助 .babelrc 去解析 TypeScript 文件再進行測試

安裝依賴

npm?install?--save-dev?@babel/preset-typescript

**改寫 **.babelrc

{???"presets":?["@babel/preset-env",?"@babel/preset-typescript"]?}

為了解決編輯器對 jest 斷言方法的類型報錯,如 test、expect 的報錯,你還需要安裝

npm?install?--save-dev?@types/jest

./get.ts

/***?訪問嵌套對象,避免代碼中出現類似?user?&&?user.personalInfo???user.personalInfo.name?:?null?的代碼*/
export?function?get<T>(object:?any,?path:?Array<number?|?string>,?defaultValue?:?T)?:?T?{const?result?=?path.reduce((obj,?key)?=>?obj?!==?undefined???obj[key]?:?undefined,?object);return?result?!==?undefined???result?:?defaultValue;
}

./test/get.test.ts

import?{?get?}?from?'./get';test('測試嵌套對象存在的可枚舉屬性?line1',?()?=>?{expect(get({id:?101,email:?'jack@dev.com',personalInfo:?{name:?'Jack',address:?{line1:?'westwish?st',line2:?'washmasher',city:?'wallas',state:?'WX'}}},?['personalInfo',?'address',?'line1'])).toBe('westwish?st');
});

運行 npm run test

4ac475eaf418bf85b5c305b4affd59e2.png

5.持續監聽

為了提高效率,可以通過加啟動參數的方式讓 jest 持續監聽文件的修改,而不需要每次修改完再重新執行測試用例

改寫 package.json

"scripts":?{?????"test":?"jest?--watchAll"???},

效果

42f66b472b0f80a8c7f0c5208dd1c27a.png

5.生成測試覆蓋率報告

什么是單元測試覆蓋率?

單元測試覆蓋率是一種軟件測試的度量指標,指在所有功能代碼中,完成了單元測試的代碼所占的比例。有很多自動化測試框架工具可以提供這一統計數據,其中最基礎的計算方式為:

單元測試覆蓋率?=?被測代碼行數?/?參測代碼總行數?*?100%

如何生成?

加入?jest.config.js ?文件

module.exports?=?{//?是否顯示覆蓋率報告collectCoverage:?true,//?告訴?jest?哪些文件需要經過單元測試測試collectCoverageFrom:?['get.ts',?'sum.ts',?'src/utils/**/*'],
}

再次運行效果

38975e7da596ab75ce013c2e7ce2fb7f.png

參數解讀

參數名含義說明
% stmts語句覆蓋率是不是每個語句都執行了?
% Branch分支覆蓋率是不是每個 if 代碼塊都執行了?
% Funcs函數覆蓋率是不是每個函數都調用了?
% Lines行覆蓋率是不是每一行都執行了?

設置單元測試覆蓋率閥值

個人認為既然在項目中集成了單元測試,那么非常有必要關注單元測試的質量,而覆蓋率則一定程度上客觀的反映了單測的質量,同時我們還可以通過設置單元測試閥值的方式提示用戶是否達到了預期質量。

jest.config.js ?文件

module.exports?=?{collectCoverage:?true,?//?是否顯示覆蓋率報告collectCoverageFrom:?['get.ts',?'sum.ts',?'src/utils/**/*'],?//?告訴?jest?哪些文件需要經過單元測試測試coverageThreshold:?{global:?{statements:?90,?//?保證每個語句都執行了functions:?90,?//?保證每個函數都調用了branches:?90,?//?保證每個?if?等分支代碼都執行了},},

上述閥值要求我們的測試用例足夠充分,如果我們的用例沒有足夠充分,則下面的報錯將會幫助你去完善

d2eb5b497cf8c56fc302b69d9fc86911.png

6.如何編寫單元測試

下面我們以 fetchEnv 方法作為案例,編寫一套完整的單元測試用例供讀者參考

編寫 fetchEnv 方法

./src/utils/fetchEnv.ts ?文件

/***?環境參數枚舉*/enum?IEnvEnum?{DEV?=?'dev',?//?開發TEST?=?'test',?//?測試PRE?=?'pre',?//?預發PROD?=?'prod',?//?生產
}/***?根據鏈接獲取當前環境參數*?@param?{string?}?url?資源鏈接*?@returns?{IEnvEnum}?環境參數*/
export?function?fetchEnv(url:?string):?IEnvEnum?{const?envs?=?[IEnvEnum.DEV,?IEnvEnum.TEST,?IEnvEnum.PRE];return?envs.find((env)?=>?url.includes(env))?||?IEnvEnum.PROD;
}

編寫對應的單元測試

./test/fetchEnv.test.ts ?文件

import?{?fetchEnv?}?from?'../src/utils/fetchEnv';describe('fetchEnv',?()?=>?{it?('判斷是否?dev?環境',?()?=>?{expect(fetchEnv('https://www.imooc.dev.com/')).toBe('dev');});it?('判斷是否?test?環境',?()?=>?{expect(fetchEnv('https://www.imooc.test.com/')).toBe('test');});it?('判斷是否?pre?環境',?()?=>?{expect(fetchEnv('https://www.imooc.pre.com/')).toBe('pre');});it?('判斷是否?prod?環境',?()?=>?{expect(fetchEnv('https://www.imooc.prod.com/')).toBe('prod');});it?('判斷是否?prod?環境',?()?=>?{expect(fetchEnv('https://www.imooc.com/')).toBe('prod');});
});

執行結果

0e5b535d7dda6f4ad6860d180abfa892.png

7.常用斷言方法

關于斷言方法有很多,這里僅摘出常用方法,如果你想了解更多,你可以去 Jest 官網 API (https://www.jestjs.cn/docs/expect)?部分查看

.not 修飾符允許你測試結果不等于某個值的情況

./test/sum.test.js

import?{?sum?}?from?'./sum';test('sum(2,?4)?不等于?5',?()?=>?{expect(sum(2,?4)).not.toBe(5);
})

.toEqual 匹配器會遞歸的檢查對象所有屬性和屬性值是否相等,常用來檢測引用類型

./src/utils/userInfo.js

export?const?getUserInfo?=?()?=>?{return?{name:?'moji',age:?24,}
}

./test/userInfo.test.js

import?{?getUserInfo?}??from?'../src/userInfo.js';test('getUserInfo()返回的對象深度相等',?()?=>?{expect(getUserInfo()).toEqual(getUserInfo());
})test('getUserInfo()返回的對象內存地址不同',?()?=>?{expect(getUserInfo()).not.toBe(getUserInfo());
})

.toHaveLength 可以很方便的用來測試字符串和數組類型的長度是否滿足預期

./src/utils/getIntArray.js

export?const?getIntArray?=?(num)?=>?{if?(!Number.isInteger(num))?{throw?Error('"getIntArray"只接受整數類型的參數');}return?[...new?Array(num).keys()];
};

./test/getIntArray.test.js

./test/getIntArray.test.js
import?{?getIntArray?}??from?'../src/utils/getIntArray';test('getIntArray(3)返回的數組長度應該為3',?()?=>?{expect(getIntArray(3)).toHaveLength(3);
})

.toThorw 能夠讓我們測試被測試方法是否按照預期拋出異常

但是需要注意的是:我們必須使用一個函數將被測試的函數做一個包裝,正如下面 getIntArrayWrapFn 所做的那樣,否則會因為函數拋出錯誤導致該斷言失敗。

./test/getIntArray.test.js

import?{?getIntArray?}??from?'../src/utils/getIntArray';test('getIntArray(3.3)應該拋出錯誤',?()?=>?{function?getIntArrayWrapFn()?{getIntArray(3.3);}expect(getIntArrayWrapFn).toThrow('"getIntArray"只接受整數類型的參數');
})

.toMatch 傳入一個正則表達式,它允許我們來進行字符串類型的正則匹配

./test/userInfo.test.js

import?{?getUserInfo?}??from?'../src/utils/userInfo.js';test("getUserInfo().name?應該包含'mo'",?()?=>?{expect(getUserInfo().name).toMatch(/mo/i);
})

測試異步函數

./servers/fetchUser.js

/**?*?獲取用戶信息
*/
export?const?fetchUser?=?()?=>?{return?new?Promise((resole)?=>?{setTimeout(()?=>?{resole({name:?'moji',age:?24,})},?2000)})
}

./test/fetchUser.test.js

import?{?fetchUser?}?from?'../src/fetchUser';test('fetchUser()?可以請求到一個用戶名字為?moji',?async?()?=>?{const?data?=??await?fetchUser();expect(data.name).toBe('moji')
})

這里你可能看到這樣一條報錯

59c7eee7d3bb58f122d5dc3df71892d4.png

這是因為?@babel/preset-env?不支持 async await 導致的,這時候就需要對 babel 配置進行增強,可以安裝 @babel/plugin-transform-runtime 這個插件解決

npm?install?--save-dev?@babel/plugin-transform-runtime

同時改寫 .babelrc

{"presets":?["@babel/preset-env",?"@babel/preset-typescript"],"plugins":?["@babel/plugin-transform-runtime"]
}

再次運行就不會出現報錯了

cc0ea7f01199b827ac939d3f7f169fa7.png

.toContain 匹配對象中是否包含

./test/toContain.test.js

const?names?=?['liam',?'jim',?'bart'];test('匹配對象是否包含',?()?=>?{expect(names).toContain('jim');
})

檢查一些特殊的值(null,undefined 和 boolean)

toBeNull?僅匹配?null
toBeUndefined?僅匹配?undefined
toBeDefined?與…相反?toBeUndefined
toBeTruthy?匹配?if?語句視為?true?的任何內容
toBeFalsy?匹配?if?語句視為?false?的任何內容檢查數字類型(number)
toBeGreaterThan?大于
toBeGreaterThanOrEqual?至少(大于等于)
toBeLessThan?小于
toBeLessThanOrEqual?最多(小于等于)
toBeCloseTo?用來匹配浮點數(帶小數點的相等)

總結

以上就是文章全部內容,相信你閱讀完這篇文章后,已經掌握了前端單元測試的基本知識,甚至可以按照文章教學步驟,現在就可以在你的項目中接入單元測試。同時在閱讀過程中如果你有任何問題,或者有更好見解,更好的框架推薦,歡迎你在評論區留言!

也許在你閱讀這篇文章之前,你本身就已掌握前端單元測試技能了,甚至已經是這個領域的大牛了,那么首先我感到非常榮幸,同時也誠懇的邀請你在評論區提出寶貴意見,我在這里提前說聲謝謝!

最后感謝你在百忙之中抽出時間閱讀這篇文章,送人玫瑰,手有余香,如果你覺得文章對你有所幫助,希望可以幫我點個贊!

最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進群。

推薦閱讀

整整4個月了,盡全力組織了源碼共讀活動~
我歷時3年才寫了10余篇源碼文章,但收獲了100w+閱讀

老姚淺談:怎么學JavaScript?

我在阿里招前端,該怎么幫你(可進面試群)

786d3f26ab03340e8d1385c49740e9cc.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》10余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助1000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

dad245802d13cf9753f0e5e9e43d8d07.png

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275137.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275137.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275137.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

xd可以用ui動效效果嗎_通過動畫使UI設計栩栩如生:Adobe XD和After Effects

xd可以用ui動效效果嗎Note — If you don’t fancy splashing out on an Adobe license, you can trial their products for 14 days each. That should give you more than enough time to play, check it out.注意—如果您不愿意花錢購買Adobe許可證&#xff0c;則可以分別試…

BookMarklet:瑞士軍刀你用了嗎?

Bookmarklet 是一段隱藏在鏈接后面的js代碼&#xff0c;可以收藏在收藏夾。通過這段代碼&#xff0c;我們可以跨瀏覽器&#xff08;當然&#xff0c;也跨平臺&#xff09;實現一些工具。比起瀏覽器插件來說&#xff0c;使用更加方便。典型的&#xff0c;dict.cn 網站的工具和有…

第十二周編程總結

這個作業屬于那個課程C語言程序設計II這個作業要求在哪里https://pintia.cn/problem-sets/1127748174659035136/problems/1127749414029729792我在這個課程的目標是更好的學習函數這個作業在那個具體方面幫助我實現目鍛煉了我的編程能力參考文獻c語言程序設計26-1 計算最長的字…

可能是全網首個前端源碼共讀活動,誠邀加入學習

大家好&#xff0c;我是若川。從8月份到現在11月結束了。每周一期&#xff0c;一起讀200行左右的源碼&#xff0c;撰寫輔助文章&#xff0c;截止到現在整整4個月了。由寫有《學習源碼整體架構系列》20余篇的若川【若川視野公眾號號主】傾力組織&#xff0c;召集了各大廠對于源碼…

現代游戲中的UX趨勢

ux設計中的各種地圖游戲UX (GAMES UX) Even though websites and games have matured side-by-side over the past few decades, games have a long and detailed history of user experience. Sure, it was scrappy and fairly rudimentary initially, but the only way you c…

SQL Server 2008 安裝過程中遇到“性能計數器注冊表”..

Windows 2008 系統 SQL Server 2008 性能計數器注冊表作者&#xff1a; 來源&#xff1a; 時間&#xff1a;2010-6-13 完美集成、增強 KindEditor HTML 編輯器今天跟隨部門老大去現場學習&#xff0c;安裝 Windows208 下 SQL Server2008&#xff0c…

你提交代碼前沒有校驗?巧用gitHooks解決

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行四個月了&#xff0c;很多小伙伴表示收獲頗豐。想學源碼&#xff0c;極力推薦訂閱我寫的《學習…

Linux下自動化測試環境的搭建

1.安裝Linux虛擬機&#xff0c;詳情參考 https://blog.csdn.net/qq_22770715/article/details/78558374 https://www.cnblogs.com/Q277227/p/8176564.html 1.1 需要確定IP &#xff0c;使用 ifconfig 1.2 linux的用戶名跟密碼&#xff1b; 1.3 確定可以遠程ssh登錄&…

code craft_以Craft.io為先—關于我們行業的實踐職業道路的系列

code craft重點 (Top highlight)For the past two decades, digital product design / UX has been shifting to become a more strategic discipline within organizations. Partially because business leaders have started to pay attention to how design-driven companie…

Nginx+httpd反代實現動靜分離

什么是動靜分離為了提高網站的響應速度&#xff0c;減輕程序服務器&#xff08;apachephp&#xff0c;nginxphp等&#xff09;的負載&#xff0c;對于靜態資源比如圖片&#xff0c;js&#xff0c;css&#xff0c;html等靜態文件&#xff0c;我們可以在反向代理服務器中設置&…

(建議收藏)前端面試必問的十六條HTTP網絡知識體系

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行四個月了&#xff0c;很多小伙伴表示收獲頗豐。想學源碼&#xff0c;極力推薦訂閱我寫的《學習…

了解 DB2 Version 9.5 中的全局變量(轉)

轉自&#xff1a;http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0711zubiri/ 簡介 在關系數據庫系統內部&#xff0c;應用程序和實際數據庫之間的主要交互都是以會話或連接的 SQL 語句形式來實現的。過去&#xff0c;為了在相同會話中實現不同 SQL 語句之…

jQuery新版本加載json注意事項。

jQuery在1.4版本后&#xff0c;采用了更為嚴格的json解析方式&#xff0c;所以所有內容都必須要有雙引號。比如以前{key:”28CATEGORY”,status:”0″}是沒問題的。但升級成1.4后&#xff0c;都必須加上雙引號&#xff1a;{“key” : “28CATEGORY”,“status” : “0″}如果你…

多邊形的時針方向與法線方向

從相反的法線方向觀察&#xff0c;順時針還是逆時針是相反的。 多邊形的時針方向與法線方向的關系呈右手法則關系。 GoogleEarth中的面具有時針方向&#xff0c;法線方向為正向&#xff0c;反之為負向 GoogleEarth的垂面在法線方向為亮色&#xff0c;反向為暗色 GoogleEarth的水…

裂墻推薦!再也不用求后端給接口了...

大家好&#xff0c;我是若川。今天咱們來介紹一款強大的云服務平臺&#xff01;MemFire Cloud注冊即享5GB存儲空間、每月100萬讀額度和每月10萬寫額度。平臺入口&#xff1a;https://memfiredb.com/今天&#xff08;12月10號&#xff09;還有限時的送書活動&#xff01;感興趣的…

1.今日標簽:視頻價值一千字

I love the App Store. It looks and works better than ever. But also, I love tricky design challenges. How do you improve something that already works great?我喜歡App Store。 它的外觀和工作比以往更好。 但是我也很棘手 設計挑戰。 您如何改善已經很好的工作&a…

Android service 小研究

最近同學搞起了Android開發&#xff0c;自己也撿起來這個玩意來看看。這里先研究一下service Service是安卓系統提供的四種組件之一&#xff0c;功能與activity類似&#xff0c;只不過沒有activity 的使用頻率高。顧名思義Service就是運行在后臺的一種服務程序一般很少與用戶交…

螞蟻金服瘋了嗎?大動作,非裁員,年底全員漲薪又漲假期!!!

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。以下分享一篇水文&#…

Android工程師轉型Java后端開發之路,自己選的路,跪著也要走下去!

本文是公眾號讀者jianfeng投稿的面試經驗恭喜該同學成功轉型目錄&#xff1a;毅然轉型&#xff0c;沒頭蒼蠅制定目標&#xff0c;系統學習面試經歷毅然轉崗&#xff0c;沒頭蒼蠅首先&#xff0c;介紹一下我的背景。本人坐標廣州&#xff0c;2016年畢業于一個普通二本大學&#…

書呆子rico_尋找設計和類型書呆子的清道夫

書呆子ricoI studied graphic design at an art school where typography was a core focus. I took 3 levels of typography classes and nearly lost my mind! But even before I studied type, I had a soft spot for signage. It’s one of the themes I enjoy shooting mo…