jueves, febrero 24, 2022

Mocks everywhere...

 Ultimamente he vuelto a java (legacy) y me ha dado por testear (como sino 😅) y he descubierto dos trickiñuelas interesantes para codigos legacy/static...

La primera es... como mockeamos un ResourceBundle (ya sabes... se usa internamente dentro de un cliente... que tampoco puedes mockear, asi facil) asi que ... ¿como haces para apuntar el cliente a un mockserver por ejemplo, sino tienes acceso a cambiarle desde el test (sin usar otro properties) la url?

Pues aqui lo cuentan, "caches" y quien llama primero...

@Test
public void myTest()
{
    // In your Test's init phase run an initial "getBundle()" call
    // with your control.  This will cause ResourceBundle to cache the result.
    ResourceBundle rb1 = ResourceBundle.getBundle( "blah", myControl );

    // And now calls without the supplied Control will still return
    // your mocked bundle.  Yay!
    ResourceBundle rb2 = ResourceBundle.getBundle( "blah" );
}

ResourceBundle.Control myControl = new ResourceBundle.Control()
{
    public ResourceBundle newBundle( String baseName, Locale locale, String format,
            ClassLoader loader, boolean reload )
    {
        return myBundle;
    }
};
ResourceBundle myBundle = new ResourceBundle()
{
    protected void setParent( ResourceBundle parent )
    {
      // overwritten to do nothing, otherwise ResourceBundle.getBundle(String)
      //  gets into an infinite loop!
    }

    TreeMap<String, String> tm = new TreeMap<String, String>();

    @Override
    protected Object handleGetObject( String key )
    {
        return tm.get( key );
    }

    @Override
    public Enumeration<String> getKeys()
    {
        return Collections.enumeration( tm.keySet() );
    }
};

Y cuando lo que quieres mockear (solo con mockito, nada de power) es un metodo estatico (que se habre en un hilo, aqui la gracia) pues aqui lo cuentan... (en el fondo algo similar a lo anterior si te fijas.

Executor executor = you executor....;
doAnswer(new Answer<Object>() {
    public Object answer(InvocationOnMock invocation)
        throws Exception {
        Object[] args = invocation.getArguments();
        Runnable runnable = (Runnable)args[0];
        try (MockedConstruction<SomeClass> mockedConstructor = Mockito.mockConstruction(SomeClass.class);
              MockedStatic<SomeStaticUtil> mockedUtil = mockStatic(SomeStaticUtil.class))
        {
            ....do mocks things
            runnable.run();
        }
        return null;
    }
}).when(executor).execute(any());

 Pues ale... a mockear se a ha dicho.