Getting Started with AssertJ - AssertJ 155

Getting Started with AssertJ – AssertJ 155

  • Post author:
  • Post category:RD / AssertJ
  • Post comments:0 Comments
  • Post last modified:2023-09-19

Getting Started with AssertJ

如何開始撰寫斷言,驗證單元測試程式碼,首先需要將物件傳遞給 Assertions.assertThat 方法,然後再執行實際的斷言,支援了一系列類別和實用方法,像是 Standard Java 、 Java 8 、 Guava 及靜態方法 allOf 、 byLessThan 、 contentOf 、 entry 、 within 等輔助方法,透過 AssertJ Getting Started 流式斷言,可以讓開發者體驗更流暢的驗證斷言,更方便快速撰寫單元測試,本篇增加了範例,透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- spring_boot_168
       |               +- test
       |                   +- assertj
       |                       +- GettingStartedAssertJTest.java   

單元測試

Improve Assertions Using Assertj 斷言物件的主要目的是取得物件以進行斷言。

Fruit

建立 Fruit 類別,覆寫 toString ,定義屬性和方法,用來建立一個物件。

	@NoArgsConstructor
	@Getter
	@Setter
	public static class Fruit {
		private String name;
		private double quantity;
		private int type;
		private List<String> origins = new ArrayList<>();

		public Fruit(String name, double quantity, int type) {
			this.name = name;
			this.quantity = quantity;
			this.type = type;
		}

		public String toString() {
			ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
			builder.appendSuper(super.toString());
			builder.append("name", name);
			builder.append("quantity", quantity);
			builder.append("type", type);
			builder.append("origins", origins);
			return builder.toString();
		}
	}

Object Assertions

驗證物件是否符合條件,若不成立,則會拋出 AssertionError ,當 isEqualTo 比較物件引用時會測試失敗,如果想比較它們的內容,要使用 usingRecursiveComparison ,遞迴比較屬性是否相等。

	@Test
	public void objectAssertions() {
		Fruit apple = new Fruit("Apple", Double.MAX_VALUE, 1, Arrays.asList("Australia"));
		Fruit apple2 = new Fruit("Apple", Double.MAX_VALUE, 1, Arrays.asList("Australia"));
		System.out.println(apple);
		System.out.println(apple2);

		assertThatCode(() -> {
			assertThat(apple).isEqualTo(apple2);
		}).isInstanceOf(AssertionError.class);

		// @Deprecated
		assertThat(apple).isEqualToComparingFieldByFieldRecursively(apple2);
		// use
		assertThat(apple).usingRecursiveComparison().isEqualTo(apple2);
	}
{"name":"Apple","quantity":1.7976931348623157E308,"type":1,"origins":[Australia]}
{"name":"Apple","quantity":1.7976931348623157E308,"type":1,"origins":[Australia]}

Class Assertions

Improve Assertions Using Assertj 驗證類別是否符合條件,若不成立,則會拋出 AssertionError 。

	@Test
	public void classAssertions() {
		Class<?> clazz = List.class;
		System.out.println(clazz);
		assertThat(clazz).isInterface().isPublic();

		Class<?> clazz2 = Collection.class;
		System.out.println(clazz2);
		assertThat(clazz2).isAssignableFrom(clazz).hasNoSuperclass().hasPublicMethods("add");
	}
interface java.util.List
interface java.util.Collection

File Assertions

Improve Assertions Using Assertj 驗證檔案是否符合條件,若不成立,則會拋出 AssertionError 。

	@Test
	public void fileAssertions() {
		File file = new File("./build.gradle");
		System.out.println(file);
		assertThat(file).exists().isFile().isRelative();
		assertThat(file).canRead().canWrite();

		File file2 = new File("./README.md");
		System.out.println(file2);
		assertThat(contentOf(file2)).startsWith("# Ruoxue").contains("www.ruoxue.org");
	}
.\build.gradle
.\README.md

InputStream Assertions

Improve Assertions Using Assertj 驗證 InputStream 是否符合條件,若不成立,則會拋出 AssertionError 。

	@Test
	public void inputStreamAssertions() {
		byte[] value = "AssertJ".getBytes();
		System.out.println(Arrays.toString(value));
		InputStream inputStream = new ByteArrayInputStream(value);
		assertThat(inputStream).isNotEmpty();

		byte[] intValue = BigInteger.valueOf(155).toByteArray();
		System.out.println(Arrays.toString(intValue));
		InputStream inputStream2 = new ByteArrayInputStream(intValue);
		assertThat(inputStream2).isNotNull();
	}
[65, 115, 115, 101, 114, 116, 74]
[0, -101]

Throwable Assertions

Guide to Assertj 驗證拋出例外,若不成立,則會拋出 AssertionError 。

	@Test
	public void throwableAssertions() {
		List<String> list = Arrays.asList("AssertJ", "155");
		assertThatThrownBy(() -> {
			list.get(2);
		}).isInstanceOf(IndexOutOfBoundsException.class);

		assertThatCode(() -> list.get(2)).isInstanceOf(IndexOutOfBoundsException.class);
	}
[{"name":"Durian","quantity":1.7976931348623157E308,"type":2,"origins":[]}, {"name":"Guava","quantity":1.0,"type":2,"origins":[]}, {"name":"Pitaya","quantity":-1.0,"type":2,"origins":[]}]
[1, 2, 3, 4, 5]

Describing Assertions

Guide to Assertj 設定驗證描述,當驗證失敗時,顯示自定義訊息。

	@Test
	public void describingAssertions() {
		Fruit banana = new Fruit("Banana", 1, 3);
		try {
			assertThat(banana.getType()).as("%s's type should be equal to 2", banana.getName()).isEqualTo(2);
		} catch (AssertionError e) {
			e.printStackTrace();
			assertThat(e).hasMessageContaining("type");
		}

		String[] array = new String[] { "Durian", "Guava", "Pitaya" };
		String text = "Length expected: [" + 3 + "] but was: [" + array.length + "]";
		try {
			Supplier<String> desc = () -> text;
			assertThat(array).as(desc).hasSize(2);
		} catch (AssertionError e) {
			e.printStackTrace();
			assertThat(e).hasMessageContaining(text);
		}
	}
org.opentest4j.AssertionFailedError: [Banana's type should be equal to 2] 
expected: 2
 but was: 3
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at org.ruoxue.spring_boot_168.test.assertj.GettingStartedAssertJTest.describingAssertions(GettingStartedAssertJTest.java:125)


java.lang.AssertionError: [Length expected: [3] but was: [3]] 
Expected size: 2 but was: 3 in:
["Durian", "Guava", "Pitaya"]
	at org.ruoxue.spring_boot_168.test.assertj.GettingStartedAssertJTest.describingAssertions(GettingStartedAssertJTest.java:135)

GettingStartedAssertJTest.java

Guide to Assertj 新增單元測試,驗證是否符合預期。

package org.ruoxue.spring_boot_168.test.assertj;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.contentOf;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.junit.jupiter.api.Test;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

public class GettingStartedAssertJTest {

	@NoArgsConstructor
	@Getter
	@Setter
	@Builder
	public static class Fruit {
		private String name;
		private double quantity;
		private int type;
		private List<String> origins = new ArrayList<>();

		public Fruit(String name, double quantity, int type, List<String> origins) {
			this.name = name;
			this.quantity = quantity;
			this.type = type;
			this.origins = origins;
		}

		public Fruit(String name, double quantity, int type) {
			this(name, quantity, type, new ArrayList<>());
		}

		public String toString() {
			ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
			builder.appendSuper(super.toString());
			builder.append("name", name);
			builder.append("quantity", quantity);
			builder.append("type", type);
			builder.append("origins", origins);
			return builder.toString();
		}
	}

	@Test
	public void objectAssertions() {
		Fruit apple = new Fruit("Apple", Double.MAX_VALUE, 1, Arrays.asList("Australia"));
		Fruit apple2 = new Fruit("Apple", Double.MAX_VALUE, 1, Arrays.asList("Australia"));
		System.out.println(apple);
		System.out.println(apple2);

		assertThatCode(() -> {
			assertThat(apple).isEqualTo(apple2);
		}).isInstanceOf(AssertionError.class);

		// @Deprecated
		assertThat(apple).isEqualToComparingFieldByFieldRecursively(apple2);
		// use
		assertThat(apple).usingRecursiveComparison().isEqualTo(apple2);
	}

	@Test
	public void classAssertions() {
		Class<?> clazz = List.class;
		System.out.println(clazz);
		assertThat(clazz).isInterface().isPublic();

		Class<?> clazz2 = Collection.class;
		System.out.println(clazz2);
		assertThat(clazz2).isAssignableFrom(clazz).hasNoSuperclass().hasPublicMethods("add");
	}

	@Test
	public void fileAssertions() {
		File file = new File("./build.gradle");
		System.out.println(file);
		assertThat(file).exists().isFile().isRelative();
		assertThat(file).canRead().canWrite();

		File file2 = new File("./README.md");
		System.out.println(file2);
		assertThat(contentOf(file2)).startsWith("# Ruoxue").contains("www.ruoxue.org");
	}

	@Test
	public void inputStreamAssertions() {
		byte[] value = "AssertJ".getBytes();
		System.out.println(Arrays.toString(value));
		InputStream inputStream = new ByteArrayInputStream(value);
		assertThat(inputStream).isNotEmpty();

		byte[] intValue = BigInteger.valueOf(155).toByteArray();
		System.out.println(Arrays.toString(intValue));
		InputStream inputStream2 = new ByteArrayInputStream(intValue);
		assertThat(inputStream2).isNotNull();
	}

	@Test
	public void throwableAssertions() {
		List<String> list = Arrays.asList("AssertJ", "155");
		assertThatThrownBy(() -> {
			list.get(2);
		}).isInstanceOf(IndexOutOfBoundsException.class);

		assertThatCode(() -> list.get(2)).isInstanceOf(IndexOutOfBoundsException.class);
	}

	@Test
	public void describingAssertions() {
		Fruit banana = new Fruit("Banana", 1, 3);
		try {
			assertThat(banana.getType()).as("%s's type should be equal to 2", banana.getName()).isEqualTo(2);
		} catch (AssertionError e) {
			e.printStackTrace();
			assertThat(e).hasMessageContaining("type");
		}

		String[] array = new String[] { "Durian", "Guava", "Pitaya" };
		String text = "Length expected: [" + 3 + "] but was: [" + array.length + "]";
		try {
			Supplier<String> desc = () -> text;
			assertThat(array).as(desc).hasSize(2);
		} catch (AssertionError e) {
			e.printStackTrace();
			assertThat(e).hasMessageContaining(text);
		}
	}
}

心得分享

Assertj Guide 支援物件、類別、檔案、例外等進行斷言,驗證是否符合條件,並可以設定驗證描述,當驗證失敗時,顯示自定義訊息,善用 Guide to Assertj 將提升不少驗證效率,縮短撰寫單元測試的時間。

發佈留言