日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 不识别enum_关于java:Unit Test for Enum值不存在?

發布時間:2024/9/27 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 不识别enum_关于java:Unit Test for Enum值不存在? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先是一些示例代碼...

枚舉:

public enum TestEnum {

YES,

NO

}

一些代碼:

public static boolean WorkTheEnum(TestEnum theEnum) {

switch (theEnum) {

case YES:

return true;

case NO:

return false;

default:

// throws an exception here

}

}

問題:

我從其他開發人員的不同代碼中導入了TestEnum。 因此它實際上可以改變。 對于這種情況,我想要一個單元測試來實際檢查該不存在的值。 但是我根本不知道如何使用Mockito和JUnit做到這一點。

這部分當然不起作用:

@Test(expected=Exception.class)

public void DoesNotExist_throwsException() throws Exception {

when(TestEnum.MAYBE).thenReturn(TestEnum.MAYBE);

WorkTheEnum(TestEnum.MAYBE);

}

我找到了一個使用PowerMock的示例,但無法使其與Mockito一起使用。

有任何想法嗎?

我沒有足夠的信心聲稱這是答案,但是:是否不可能做TestEnum notAValidEnum = Mockito.mock(TestEnum.class);,然后將其提供給WorkTheEnum() ...?

可能重復:stackoverflow.com/questions/5323505

可能相關:stackoverflow.com/questions/28013717/

以@assylias的答案為基礎,我認為這是您可以做的最好的事情:

List unknown = new ArrayList<>();

for (TestEnum e : TestEnum.values())

unknown.add(e.name());

unknown.removeAll(Arrays.asList("YES","NO"));

if (unknown.isEmpty()) {

// Not possible to reach default case, do whatever you need to do

} else {

TestEnum notIncluded = TestEnum.valueOf(unknown.get(0));

workTheEnum(notIncluded);

}

由于enum switch語句的編譯方式,不可能(AFAIK)偽造switch語句中不存在的enum值。即使您通過反射擺弄enum實例中的內部ordinal字段,switch語句也將給出ArrayIndexOutOfBoundsException而不是陷入default情況。

由于上面提到的ArrayIndexOutOfBoundsException,以下代碼看起來可能可行,但無效:

TestEnum abused = TestEnum.YES;

try {

Class< ? > c = abused.getClass().getSuperclass();

Field[] declaredFields = c.getDeclaredFields();

Field ordinalField = null;

for (Field e : declaredFields) {

if (e.getName().equals("ordinal")) {

ordinalField = e;

}

}

ordinalField.setAccessible(true);

ordinalField.setInt(abused, TestEnum.values().length);

workTheEnum(abused);

} catch (Exception e) {

e.printStackTrace(System.err);

}

好的,這可能對您有用。這很hacky,所以對我來說,可能比沒有100%代碼覆蓋率YMMV更糟糕。它通過用包含全零的數組替換枚舉有序查找數組來工作,這屬于默認情況。

// Setup values - needs to be called so that

// $SWITCH_TABLE$FooClass$BarEnum is initialised.

workTheEnum(TestEnum.YES);

workTheEnum(TestEnum.NO);

// This is the class with the switch statement in it.

Class< ? > c = ClassWithSwitchStatement.class;

// Find and change fields.

Map changedFields = new HashMap<>();

Field[] declaredFields = c.getDeclaredFields();

try {

for (Field f : declaredFields) {

if (f.getName().startsWith("$SWITCH_TABLE$")) {

f.setAccessible(true);

int[] table = (int[])f.get(null);

f.set(null, new int[table.length]);

changedFields.put(f, table);

}

}

workTheEnum(TestEnum.YES);

} finally {

for (Map.Entry entry : changedFields.entrySet()) {

try {

entry.getKey().set(null, entry.getValue());

} catch (Exception ex) {

ex.printStackTrace(System.err);

}

}

}

也許嘲笑不是正確的方法嗎?但是必須有一種使用反射添加值的方法,以便枚舉實際上是有效的并且具有所有這些值!

不,我不這么認為。編譯switch語句時,將生成一個數組,其中包含該時間點存在的枚舉值的所有序號。如果嘗試修改現有值以更改其序數,則編譯器生成的代碼將訪問數組范圍之外的值,并失敗并顯示ArrayIndexOutOfBoundsException。糟糕的是附加了一些執行此操作的代碼,以便您可以查看是否喜歡。

感謝您詳細的答復@msandiford。我想運氣不好。

對我來說,它僅在將f.setAccessible(true);添加到循環中時才有效(請參閱我的編輯)。這可能與Java8有關嗎?

另一個注意事項:對我來說,它不適用于Maven(->在此排除它)。一旦Maven使用開關編譯了該類,就必須再次在Eclipse中編譯該類以使測試再次在Eclipse中工作。換句話說,無論測試是否有效,編譯器都起著重要的作用。

一個簡單的怎么樣:

Set expected = new HashSet<> (Arrays.asList("YES","NO"));

Set actual = new HashSet<>();

for (TestEnum e : TestEnum.values()) actual.add(e.name());

assertEquals(expected, actual);

(使用HashSet而不是ArrayList,因為順序無關緊要)

但這只會測試枚舉的內容,而不會測試switch語句的默認路徑。

我明白了-如果要達到默認大小寫,您想確保該方法引發異常,因此您想模擬枚舉以模擬非預期值。那正確嗎?

那正是我想做的,是的。

@Feroc的問題是您無法通過反射實例化枚舉的新實例,因此我不確定mockito是否可以解決該限制...

Mockito不支持枚舉值的模擬,但powermock則支持。

嘗試這個。

我創建了自己的類來模擬它們。請映射到您自己的班級。

@RunWith(PowerMockRunner.class)

@PrepareForTest(Trail.class)

public class TrailTest {

@Before

public void setUp() {

Trail mockTrail = PowerMock.createMock(Trail.class);

Whitebox.setInternalState(mockTrail,"name","Default");

Whitebox.setInternalState(mockTrail,"ordinal", 2);

PowerMock.mockStatic(Trail.class);

expect(Trail.values()).andReturn(new Trail[]{Trail.YES, Trail.NO, mockTrail});

expect(Trail.valueOf("default value")).andReturn(mockTrail);

PowerMock.replay(Trail.class);

}

@Test(expected = RuntimeException.class)

public void test() {

Trail aDefault = Trail.valueOf("default value");

BasicTrails.find(aDefault);

}

}

這是方法:

public class BasicTrails {

public static boolean find(Trail trail) {

switch (trail) {

case YES:

return true;

case NO:

return false;

default:

throw new RuntimeException("Invalid");

}

}

這是枚舉

public enum Trail {

YES, NO;

}

謝謝你的幫助。不太確定我們是否可以在此處使用Powermock。

它只是另一個mock庫。無論如何,這取決于選擇。

如果您將代碼轉換為OP問題,則可以改善答案

@VinayVeluri:PowerMock不僅僅是另一個模擬庫。它比Mockito更強大,這就是為什么有些人不想在項目中使用它的原因。它用于測試遺留代碼,例如靜態方法無法通過Mockito等"常規"模擬庫進行測試。只要您開發一個新項目,就應該以不需要PowerMock的方式進行開發,但是Mockito就足夠了。

借助Powermock,我們可以實現此目標,因為Powermock支持模擬最終類

import org.junit.Before;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.mockito.BDDMockito;

import org.mockito.Mock;

import org.powermock.api.mockito.PowerMockito;

import org.powermock.core.classloader.annotations.PrepareForTest;

import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)

@PrepareForTest(Trail.class)

public class TrailTest {

@Mock Trail mockTrail;

@Before

public void setUp() {

PowerMockito.mockStatic(Trail.class);

BDDMockito.given(Trail.values()).willReturn(new Trail[]{Trail.YES, Trail.NO, mockTrail});

BDDMockito.given(Trail.valueOf("YES")).willReturn(mockTrail.YES);

BDDMockito.given(Trail.valueOf("NO")).willReturn(mockTrail.NO);

}

@Test

public void test() {

assertTrue(BasicTrails.find(mockTrail.valueOf("YES")));

assertFalse(BasicTrails.find(mockTrail.valueOf("NO")));

try{

Trail aDefault = mockTrail.valueOf("default value");

}catch (Exception e) {

System.out.println(e);

}

}

}

您可以嘲笑,修改或嘗試使其工作,但是有一種非常簡單的方法來做到這一點。我假設您正在使用Maven或Gradle,因此您具有main和test配置文件。

然后在主配置文件中,您將得到上面的代碼:

package my.cool.package;

public enum TestEnum {

YES,

NO

}

但是在測試配置文件中,您可以擁有另一個:

// EXACTLY SAME as above

package my.cool.package;

public enum TestEnum {

YES,

NO,

INVALID_FOR_TEST_ONLY

}

現在您可以在測試中使用新值INVALID_FOR_TEST_ONLY,并且在產品概要文件中將不可用。

有兩個缺點:

如果您更新產品枚舉,則可能還需要更新測試(如果要進行測試,則需要更新)

某些IDE可能無法正確使用此技巧,即使Maven很好理解它

總結

以上是生活随笔為你收集整理的java 不识别enum_关于java:Unit Test for Enum值不存在?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。