Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot mock 'LocaleInfo.getAvailableLocaleNames' (1.1.3->1.1.4 Regression) #36

Open
ankon opened this issue Jul 11, 2014 · 1 comment
Open

Comments

@ankon
Copy link

ankon commented Jul 11, 2014

In 1.1.3 it was possible to mock LocaleInfo#getAvailableLocaleNames() easily:

@GwtMock LocaleInfo localeInfo;

@Test
public void myTest() {
  when(LocaleInfo.getAvailableLocaleNames()).thenReturn(new String[] { "foo" });
  ... test stuff.
}

In 1.1.4, due to c5465ca making the LocaleInfo(Impl) a fake, this doesn't work. And, because one cannot replace the default fakes either, this essentially means my tests for locale/i18n can no longer run :/

With that said, I worked around the issue like this:

@RunWith(GwtMockitoTestRunner.class)
public class AppControllerTest {
    private static class MyFakeLocaleInfoImplProvider implements FakeProvider<LocaleInfoImpl> {
        /** If non-{@code null}: locale names to return from {@link LocaleInfo#getAvailableLocaleNames()} */
        private static String[] availableLocaleNames = null;

        public static void setAvailableLocaleNames(String... availableLocaleNames) {
            MyFakeLocaleInfoImplProvider.availableLocaleNames = availableLocaleNames;
        }

        @SuppressWarnings("unchecked")
        public static void enable() {
            try {
                Field field = GwtMockito.class.getDeclaredField("DEFAULT_FAKE_PROVIDERS");
                field.setAccessible(true);
                ((Map<Class<?>, FakeProvider<?>>) field.get(null)).put(LocaleInfoImpl.class, new MyFakeLocaleInfoImplProvider());
            } catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
                throw new RuntimeException("Cannot enable custom locales");
            }
        }

        @Override
        public LocaleInfoImpl getFake(Class<?> type) {
            return new LocaleInfoImpl() {
                @Override
                public DateTimeFormatInfo getDateTimeFormatInfo() {
                    return new DefaultDateTimeFormatInfo();
                }

                @Override
                public String[] getAvailableLocaleNames() {
                    return availableLocaleNames != null ? availableLocaleNames : super.getAvailableLocaleNames();
                }
            };
        }
    }

    @BeforeClass
    public static void setUpBeforeClass() {
        // Replace the fake LocaleInfoImpl with one that allows controlling the result of #getAvailableLocaleNames()
        // As this is a default provider we need to be quite aggressive in replacing it.
        MyFakeLocaleInfoImplProvider.enable();
    }

    @Test
    public void myTest() {
        final String localeName = "foo_BAR";
        MyFakeLocaleInfoImplProvider.setAvailableLocaleNames("foo");
        // do some testing!
    }

It would be nice if this was a tad easier to accomplish:

  • don't use anonymous classes in the default FakeProviders, so one can inherit and extend GwtMockito's fakes if needed
  • allow replacing the default fake providers (maybe using an annotation pointing to the fake provider class to use?)
@ekuefler
Copy link
Collaborator

Sorry for the regression - taking a look into this now. I think it should work like you want it to, with mocks or fakes that you've defined explicitly taking priority over the default fakes. Both of these tests pass for me:

@RunWith(GwtMockitoTestRunner.class)
public class MockTest {
  @GwtMock LocaleInfoImpl localeInfo;

  @Test
  public void myMockTest() {
    when(localeInfo.getAvailableLocaleNames()).thenReturn(new String[] {"foo"});
    assertEquals("foo", LocaleInfo.getAvailableLocaleNames()[0]);
  }
}
@RunWith(GwtMockitoTestRunner.class)
public class FakeTest {
  @Test
  public void myFakeTest() {
    GwtMockito.useProviderForType(LocaleInfoImpl.class, new FakeProvider<LocaleInfoImpl>() {
      @Override
      public LocaleInfoImpl getFake(Class<?> type) {
        return new LocaleInfoImpl() {
          @Override
          public String[] getAvailableLocaleNames() {
            return new String[] {"foo"};
          }
        };
      }
    });
    assertEquals("foo", LocaleInfo.getAvailableLocaleNames()[0]);
  }
}

I don't think your test could ever have worked as you have it written here, since LocaleInfo.getAvailableLocaleNames() is a static method that can't be mocked by Mockito. I think you will always have had to mock LocaleInfoImpl like I'm doing in my first test, so I'm not quite sure where the regression is.

Are you sure your test used to work? Do my tests work for you? Do you have a complete example of a test that passed in 1.1.3 and failed in 1.1.4?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants