首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果在线程中调用mock静态函数,则mockito mock静态函数不起作用

如果在线程中调用mock静态函数,则mockito mock静态函数不起作用
EN

Stack Overflow用户
提问于 2021-07-12 08:05:27
回答 1查看 408关注 0票数 0

android应用程序,java类需要根据NotificationManager的状态执行一些操作。

代码语言:javascript
复制
class Util {
    
        static void setupByPermission(@NonNull final Context appContext) {
            Thread t = new Thread(new Runnable() {
                public void run() {
                    try {
                        NotificationManagerCompat nm = NotificationManagerCompat.from(appContext);  // should got from stub
                        
                        boolean overallPermission = currentNotificationsPermission(nm);
                        if (overallPermission) {
                            doWithPermission();
                        } else {
                            doWithoutPermission();
                        }
                        
                    } catch (Throwable ex) {}
                }
            });
            t.start();
        }

    static boolean currentNotificationsPermission(@NonNull NotificationManagerCompat nm) {

        System.out.println("+++ enter currentNotificationsPermission("+nm+")");

        boolean overallPermission = nm.areNotificationsEnabled();// should got result from stub

        System.out.println("+++ ========= in currentNotificationsPermission("+nm+"), nm.areNotificationsEnabled() ==> "+overallPermission);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (overallPermission) {
                List<NotificationChannel> channels = nm.getNotificationChannels();
                boolean someChannelEnabled = channels.isEmpty();
                for (NotificationChannel channel : channels) {
                    if (channel.getImportance() != NotificationManagerCompat.IMPORTANCE_NONE) {
                        someChannelEnabled = true;
                        break;
                    }
                }
                overallPermission = overallPermission && someChannelEnabled;
            }
        }

        System.out.println("+++ --- exit =========== currentNotificationsPermission(), overallPermission:"+overallPermission);

        return overallPermission;
    }
    
}

希望存根NotificationManagerCompat.areNotificationsEnabled()以强制测试返回true或false。

使用mockito-inline 3.8.0进行测试

代码语言:javascript
复制
@Test
public void test () throws Exception  {

   try (MockedStatic<NotificationManagerCompat> nmMoc = Mockito.mockStatic(NotificationManagerCompat.class);
        MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)
        ) {

        NotificationManagerCompat nmSpy = spy(NotificationManagerCompat.from(application));
        
when(nmSpy.areNotificationsEnabled())
            .thenReturn(false);  //or true

        nmMoc.when(() -> NotificationManagerCompat.from(any(Context.class)))
            .thenReturn(nmSpy);

        // test
        final CountDownLatch latch = new CountDownLatch(1);
        utilMoc.setupByPermission(application);
        latch.await(2, TimeUnit.SECONDS);

        Mockito.verify(......);
        }
}

但是当存根在线程中时,存根不会被调用。如果存根currentNotificationsPermission(),也是如此。

让静态函数的存根在线程中工作是不是很热?

EN

回答 1

Stack Overflow用户

发布于 2021-07-12 10:04:01

你的测试似乎有一些问题:

  • 不要模仿静态方法。重构您的代码以使用接口和实现。这也会使依赖注入变得更容易。
  • 读取了MockedStatic的Javadoc。它显式地告诉你模拟只在原始线程上工作。
  • 你的代码是如何编译的?utilMoc是一个MockedStatic<Util>,所以你如何在它上面调用setupByPermission
  • 假设你已经模拟了Util,在Util上调用方法无论如何都不会调用‘utilMoc’方法,除非你告诉它这样做。参见下面的例子。
  • 单元测试多线程代码是困难的。有一个负责执行Runnable的组件。在测试中,使用一个在当前线程上运行Runnable的虚拟实现。

代码语言:javascript
复制
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class TestExample {
    public static class Foo {
        public static String bar() {
            return "bar";
        }
    }
    @Test
    public void aTest() {
        try (MockedStatic<Foo> foo = Mockito.mockStatic(Foo.class)) {
// without this line Foo.bar() will return null
            when(Foo.bar()).thenCallRealMethod();
            assertThat(Foo.bar()).isEqualTo("bar");
        }
    }
}

虽然人们已经投入了大量的工作来使模拟静态方法成为可能,但正如你所看到的,这仍然不是简单的事情。避免这种情况所需的重构很简单,而且还有其他好处。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68340718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档