如何将静态方法重载/覆盖为 return 另一个值?
How to overload / override static method to return an other value?
基本上我正在尝试模拟静态 class 进行单元测试。
示例:
class Library {
public static boolean isActivated() {
return false;
}
}
class Test {
public static void main(String[] args) {
// some magic
if (Library.isActivated()) {
System.out.println("'some magic' works!");
} else {
System.out.println("fail");
}
}
}
some magic
需要什么才能使 Library.isActivated()
return true
.
是否有一些特殊的方法可以在不更改 Library
的源代码的情况下执行此操作?
据我所知,这在 java 中是不可能的,但我对 Reflection 不是很熟悉,我认为这可能是可能的。
静态方法不是虚拟的,因此不能被覆盖。重载不会满足您的目的,因为它涉及具有相同名称但参数类型不同的方法,并且在任何情况下,您都需要修改 class Library
以添加重载。 Java 语言没有为不同的 class 提供对现有 Library
class.
施加重载的方法
总体而言,这反映了依赖静态方法和非最终静态数据的更广泛问题。
Is there some special way to do this without changing the source code of Library?
As far as I know this is not possible in java but I'm not very familiar with Reflection I thought this might be possible with it.
反射也不行。您需要做的是加载与您显示的版本不同的 class 版本。这可以通过
实现
- 精心管理class路径
Library
不同版本的即时合成
- 和
ClassLoaders
一起玩游戏
如果你想限制替换的范围 class —— 这样你的替换就不会在 other 测试中使用 —— 那么你可能需要行使 ClassLoader
选项,尽管这不一定排除其他两个。这很重要。
但是,您可能能够找到一个可以为您处理所有这些的模拟库。
绝对不能覆盖静态方法。但是,您可以通过大量工作来模拟静态方法。通常,模拟静态方法不是一个好兆头。幸运的是,如果你需要的话,有一些图书馆可以做到这一点。
Mockito 添加了对此的支持,Baeldung 有一个很好的教程演示了如何做到这一点:https://www.baeldung.com/mockito-mock-static-methods#mocking-a-no-argument-static-method。
基于教程:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
@Test
void mockLibraryIsActivated() {
// Before mocking the static method is going to return false
assertFalse(Library.isActivated());
// Using MockedStatic to mock the method
try (MockedStatic<Library> utilities = Mockito.mockStatic(Library.class)) {
utilities.when(Library::isActivated).thenReturn(true);
// Perform your test, the mock only works within the try block
assertTrue(Library.isActivated());
}
// Mock is no longer active
assertFalse(Library.isActivated());
}
对此的一个关键限制是模拟仅适用于它定义的代码块。因此,如果您有另一个单元测试,您也必须在该单元测试中模拟它。
如果你真的想钻进兔子洞,你可以看看 MockitoCore.mockStatic
在 GitHub 仓库中是如何实现的:https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/internal/MockitoCore.java.
基本上我正在尝试模拟静态 class 进行单元测试。
示例:
class Library {
public static boolean isActivated() {
return false;
}
}
class Test {
public static void main(String[] args) {
// some magic
if (Library.isActivated()) {
System.out.println("'some magic' works!");
} else {
System.out.println("fail");
}
}
}
some magic
需要什么才能使 Library.isActivated()
return true
.
是否有一些特殊的方法可以在不更改 Library
的源代码的情况下执行此操作?
据我所知,这在 java 中是不可能的,但我对 Reflection 不是很熟悉,我认为这可能是可能的。
静态方法不是虚拟的,因此不能被覆盖。重载不会满足您的目的,因为它涉及具有相同名称但参数类型不同的方法,并且在任何情况下,您都需要修改 class Library
以添加重载。 Java 语言没有为不同的 class 提供对现有 Library
class.
总体而言,这反映了依赖静态方法和非最终静态数据的更广泛问题。
Is there some special way to do this without changing the source code of Library?
As far as I know this is not possible in java but I'm not very familiar with Reflection I thought this might be possible with it.
反射也不行。您需要做的是加载与您显示的版本不同的 class 版本。这可以通过
实现- 精心管理class路径
Library
不同版本的即时合成
- 和
ClassLoaders
一起玩游戏
如果你想限制替换的范围 class —— 这样你的替换就不会在 other 测试中使用 —— 那么你可能需要行使 ClassLoader
选项,尽管这不一定排除其他两个。这很重要。
但是,您可能能够找到一个可以为您处理所有这些的模拟库。
绝对不能覆盖静态方法。但是,您可以通过大量工作来模拟静态方法。通常,模拟静态方法不是一个好兆头。幸运的是,如果你需要的话,有一些图书馆可以做到这一点。
Mockito 添加了对此的支持,Baeldung 有一个很好的教程演示了如何做到这一点:https://www.baeldung.com/mockito-mock-static-methods#mocking-a-no-argument-static-method。
基于教程:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
@Test
void mockLibraryIsActivated() {
// Before mocking the static method is going to return false
assertFalse(Library.isActivated());
// Using MockedStatic to mock the method
try (MockedStatic<Library> utilities = Mockito.mockStatic(Library.class)) {
utilities.when(Library::isActivated).thenReturn(true);
// Perform your test, the mock only works within the try block
assertTrue(Library.isActivated());
}
// Mock is no longer active
assertFalse(Library.isActivated());
}
对此的一个关键限制是模拟仅适用于它定义的代码块。因此,如果您有另一个单元测试,您也必须在该单元测试中模拟它。
如果你真的想钻进兔子洞,你可以看看 MockitoCore.mockStatic
在 GitHub 仓库中是如何实现的:https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/internal/MockitoCore.java.