赞扬别人团建评论_赞扬精心设计:基于属性的测试如何帮助我成为更好的开发人员...
贊揚別人團建評論
開發人員的測試工具箱就是其中之一,很少保持不變。 可以肯定的是,一些測試實踐已被證明比其他測試更有價值,但是,我們仍在不斷尋找更好,更快和更具表現力的方法來測試我們的代碼。 基于屬性的測試 是 Java社區中鮮為人知的 ,這是Haskell員工精心制作的另一種瑰寶,并在QuickCheck論文中進行了介紹 。
Scala社區(誕生了ScalaCheck庫的Scala社區)和許多其他組織很快意識到了這種測試技術的強大功能,但是Java生態系統在相當長的一段時間內一直缺乏采用基于屬性的測試的興趣。 幸運的是,自從jqwik出現以來,情況就在慢慢變化, 以求更好。
對于許多人來說,很難掌握什么是基于屬性的測試以及如何利用它。 杰西卡·克爾 ( Jessica Kerr)的精彩演講《基于屬性的測試,更好的代碼》 ,以及有關基于屬性的測試的簡介,基于 屬性的測試模式系列的文章,是吸引您的絕佳來源,但是在今天的帖子中,我們將嘗試發現典型的Java開發人員使用jqwik進行的基于屬性的測試的實踐方面。
首先, 基于屬性的測試名稱實際上意味著什么? 每個Java開發人員首先想到的是它旨在測試所有的getter和setters(您好100%覆蓋率)嗎? 并非如此,盡管對于某些數據結構而言可能很有用。 相反,我們應該確定組件,數據結構甚至單個功能的高級特性 ,并通過提出假設有效地對其進行檢驗。
我們的第一個示例屬于“那里又回來”類別:將序列化和反序列化為JSON表示形式。 被測試的類是User POJO ,雖然很簡單,但請注意它具有OffsetDateTime類型的一個時間屬性。
public class User { private String username; @JsonFormat (pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS[SSS]]XXX" , shape = Shape.STRING) private OffsetDateTime created; ????// ... }令人驚訝的是,由于所有人都在嘗試使用自己的表示形式,因此最近幾天使用日期/時間屬性進行操作會引起問題。 如您所見,我們的合同使用的是ISO-8601互換格式,帶有可選的毫秒部分。 我們要確保的是,可以將任何有效的User實例序列化為JSON ,然后反序列化為Java對象,而不會失去任何日期/時間精度。 作為練習,讓我們嘗試首先用偽代碼來表達它:
For any user Serialize user instance to JSON Deserialize user instance back from JSON Two user instances must be identical看起來很簡單,但令人驚訝的部分出在這里:讓我們看一下如何使用jqwik庫將此偽代碼投影到真實的測試用例中。 它盡可能地接近我們的偽代碼。
@Property void @ForAll serdes( @ForAll ( "users" ) User user) throws JsonProcessingException { final String json = serdes.serialize(user); assertThat(serdes.deserialize(json)) .satisfies(other -> { assertThat(user.getUsername()).isEqualTo(other.getUsername()); assertThat(user.getCreated().isEqual(other.getCreated())).isTrue(); }); ????????Statistics.collect(user.getCreated().getOffset()); }測試用例讀起來很簡單,通常是自然的,但是顯然, jqwik的@Property和@ForAll批注后面隱藏著一些背景。 讓我們從@ForAll開始,并清除所有這些User實例的來源。 您可能猜到了,這些實例必須生成,最好以隨機方式生成。
對于大多數內置數據類型, jqwik具有一組豐富的數據提供程序( Arbitraries ),但是由于我們要處理特定于應用程序的類,因此我們必須提供自己的生成策略。 它應該能夠發出具有廣泛的用戶名以及不同時區和偏移量集合的日期/時刻的User類實例。 首先讓我們先略過提供者的實現,然后再詳細討論。
@Provide Arbitrary<User> users() { final Arbitrary<String> usernames = Arbitraries.strings().alpha().ofMaxLength( 64 ); ?final Arbitrary<OffsetDateTime> dates = Arbitraries .of(List.copyOf(ZoneId.getAvailableZoneIds())) .flatMap(zone -> Arbitraries .longs() .between(1266258398000L, 1897410427000L) // ~ +/- 10 years .unique() .map(epochMilli -> Instant.ofEpochMilli(epochMilli)) .map(instant -> OffsetDateTime.from(instant.atZone(ZoneId.of(zone))))); return Combinators .combine(usernames, dates) .as((username, created) -> new User(username).created(created)); }用戶名的來源很簡單:只是隨機字符串。 日期的來源基本上可以是2010年到2030年之間的任何日期/時間,而時區部分(因此是偏移量)是從所有可用的基于區域的區域標識符中隨機選擇的。 例如,下面是jqwik提出的一些示例。
{ "username" : "zrAazzaDZ" , "created" : "2020-05-06T01:36:07.496496+03:00" } { "username" : "AZztZaZZWAaNaqagPLzZiz" , "created" : "2023-03-20T00:48:22.737737+08:00" } { "username" : "aazGZZzaoAAEAGZUIzaaDEm" , "created" : "2019-03-12T08:22:12.658658+04:00" } { "username" : "Ezw" , "created" : "2011-10-28T08:07:33.542542Z" } { "username" : "AFaAzaOLAZOjsZqlaZZixZaZzyZzxrda" , "created" : "2022-07-09T14:04:20.849849+02:00" } { "username" : "aaYeZzkhAzAazJ" , "created" : "2016-07-22T22:20:25.162162+06:00" } { "username" : "BzkoNGzBcaWcrDaaazzCZAaaPd" , "created" : "2020-08-12T22:23:56.902902+08:45" } { "username" : "MazNzaTZZAEhXoz" , "created" : "2027-09-26T17:12:34.872872+11:00" } { "username" : "zqZzZYamO" , "created" : "2023-01-10T03:16:41.879879-03:00" } { "username" : "GaaUazzldqGJZsqksRZuaNAqzANLAAlj" , "created" : "2015-03-19T04:16:24.098098Z" } ...默認情況下, jqwik將針對1000套不同的參數值(隨機用戶實例)運行測試。 非常有用的“ 統計”容器允許收集您好奇的任何分布見解。 以防萬一,為什么不按區域偏移量收集分布呢?
... - 04 : 00 ( 94 ) : 9.40 % - 03 : 00 ( 76 ) : 7.60 % + 02 : 00 ( 75 ) : 7.50 % - 05 : 00 ( 74 ) : 7.40 % + 01 : 00 ( 72 ) : 7.20 % + 03 : 00 ( 69 ) : 6.90 % Z ( 62 ) : 6.20 % - 06 : 00 ( 54 ) : 5.40 % + 11 : 00 ( 42 ) : 4.20 % - 07 : 00 ( 39 ) : 3.90 % + 08 : 00 ( 37 ) : 3.70 % + 07 : 00 ( 34 ) : 3.40 % + 10 : 00 ( 34 ) : 3.40 % + 06 : 00 ( 26 ) : 2.60 % + 12 : 00 ( 23 ) : 2.30 % + 05 : 00 ( 23 ) : 2.30 % - 08 : 00 ( 20 ) : 2.00 % ...讓我們考慮另一個例子。 想象一下,我們決定基于用戶名屬性重新實現User類的相等性(在Java中,這意味著重寫equals和hashCode )。 這樣,對于任何一對User類實例,以下不變量必須為true:
- 如果兩個User實例具有相同的用戶名 ,則它們相等,并且必須具有相同的哈希碼
- 如果兩個User實例具有不同的username ,則它們不相等(但哈希碼不一定相同)
它非常適合基于屬性的測試,并且jqwik尤其使這種測試的編寫和維護變得微不足道。
@Provide Arbitrary<String> usernames() { return Arbitraries.strings().alpha().ofMaxLength( 64 ); } @Property void equals( @ForAll ( "usernames" ) String username, @ForAll ( "usernames" ) String other) { Assume.that(!username.equals(other)); ????????assertThat( new User(username)) .isEqualTo( new User(username)) .isNotEqualTo( new User(other)) .extracting(User::hashCode) .isEqualTo( new User(username).hashCode()); }由于我們引入了用戶名的兩個來源,因此通過假設表達的假設允許對生成的參數施加額外的約束,這可能會發生,因為它們在同一運行中都發出相同的用戶名,因此測試將失敗。
您到目前為止可能遇到的問題是:重點是什么? 當然可以在不進行基于屬性的測試和使用jqwik的情況下測試序列化/反序列化或equals / hashCode ,那么為什么還要麻煩呢? 足夠公平,但是這個問題的答案基本上深深在于我們如何進行軟件系統的設計。
總體而言, 基于屬性的測試在很大程度上受函數式編程的影響,這并不是Java的第一件事(至少現在還不是),這要輕描淡寫地說。 隨機生成測試數據本身并不是一個新穎的主意,但是至少在我看來, 基于屬性的測試鼓勵您去做的是,以更抽象的角度思考,而不是專注于單個操作(等于,比較,加法)。 ,排序,序列化...),但是它們要遵循什么樣的屬性,特征,定律和/或不變式。 當然,這感覺就像是一種外來技術,如果您愿意的話,可以改變范式,鼓勵您花更多的時間設計正確的東西。 這并不意味著從現在開始您的所有測試都必須基于屬性,但是我相信它當然應該在我們的測試工具箱的前排位置。
請在Github上找到完整的項目資源。
翻譯自: https://www.javacodegeeks.com/2020/02/in-praise-of-the-thoughful-design-how-property-based-testing-helps-me-to-be-a-better-developer.html
贊揚別人團建評論
總結
以上是生活随笔為你收集整理的赞扬别人团建评论_赞扬精心设计:基于属性的测试如何帮助我成为更好的开发人员...的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 旧版手机如何变电脑系统(旧手机变成电脑)
- 下一篇: annotations_Spring A
