2010-09-07 6 views
5

Soy un hada nueva en las pruebas unitarias y he estado aprendiendo a usar el framework jUnit para android (usando ActivityInstrumentationTestCase2) pero estoy teniendo problemas para averiguar cómo inyectar una fuente de datos simulada en y actividad, ejemplo:Técnicas de Android para fuente de datos simulada en la prueba de unidad de actividad

en el activiy tengo este

public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState,R.layout.market_screen); 
     ListView products = (ListView)findViewById(R.id.product_list); 
     MarketsAdapter adapter = new MarketsAdapter(this, new ProductDataSource()); 
     products.setAdapter(adapter); 

} 

I actualmente pasar un ProductDataSource en el adaptador que se conecta a un servicio web para tirar en productos para el adaptador. En mis pruebas, no quiero conectarme al servicio web. ¿Cuál es la mejor técnica para inyectar una fuente de datos de prueba en la actividad para probar? ¿Debo crear ProductDataSource en una instancia de la Aplicación y luego usar una Aplicación de Mock en mis pruebas para crear una fuente de datos simulada?

Gracias

que resuelven de la siguiente manera en la clase de prueba setUp() método: Coge una referencia a la ListView y establecer el origen de datos utilizando Mock setAdapter(MockDataSource). Esto debe ejecutarse en el subproceso UI usando el método runOnUiThread().

mActivity = getActivity(); 
mDataSource = new FakeDataSource();  
mMarketsListView = (ListView)mActivity.findViewById(R.id.product_list); 
mActivity.runOnUiThread(
     new Runnable() { 
     public void run() { 
      mMarketsListView.setAdapter(new MarketsAdapter(mActivity,mDataSource)); 

     } // end of run() method definition 
    } // end of anonymous Runnable object instantiation 
); // 
+0

resuelto como arriba – longhairedsi

Respuesta

7

A juzgar por su resolución, es más refiriéndose a "imitar", como apagando algunos datos de prueba. Siempre es una gran manera de avanzar en el desarrollo cuando está más interesado en la funcionalidad y realmente no le importan los detalles.

Así que solo te estoy dando esta respuesta porque dijiste que eras nuevo en pruebas unitarias. Entonces, si estuvieras escribiendo una prueba unitaria que dependiera de un ProductsDatasource, también podrías usar un marco de burla para enchufar un objeto "simulado" en lugar de anular una clase concreta. Trabajo más con .Net que con Java, pero todos mis ejemplos de código usarán JUnit y JMock para describir de lo que estoy hablando.

Burlarse funciona creando objetos simulados "concretos" para las interfaces. Recuerde, una interfaz es solo un contrato que dice que su clase proporcionará los métodos especificados.

Así que decir que tenía una aplicación ProductsDatasource interfaz de este modo:

public interface IProductsDatasource { 

    public List<Product> getProducts(); 

} 

y un tipo concreto de:

public class ProductsDatasource implements IProductsDatasource { 

    private List<Product> mProducts; 

    public ProductsDatasource(List<Product> products) { 
     mProducts = products; 
    } 

    public List<Product> getProducts() { 
     return mProducts; 
    } 

} 

Ahora, que usted es la unidad de pruebas de algo, decir TargetAdapter, que admite ProductsDatasource. Si crea un nuevo ProductsDatasource, entonces tendría una dependencia. La prueba de su unidad ahora dependerá de la clase que esté probando, y ProductsDatasource. Tal vez ya haya probado ProductsDatasource en otra suite.

public class TargetAdapter { 

    private IProductsDatasource mDatasource; 

    public TargetAdapter(IProductsDatasource datasource) { 
     mDatasource = datasource; 
    } 

    public List<Product> products() { 
     return mDatasource.getProducts(); 
    } 

} 

Así que aquí es un caso de prueba, sin burlarse, que los detalles de lo que estoy hablando.

@Test 
public void TargetAdapterReturnsProducts() { 

    List<Product> data = new ArrayList<Product>(); 
    data.add(new Product("Sample Product 1")); 
    data.add(new Product("Sample Product 2")); 
    data.add(new Product("Sample Product 3")); 


    TargetAdapter adapter = new TargetAdapter(new ProductsDatasource(data)); // See the dependency 
    List<Product> products = adapter.products(); 

    Assert.assertNotNull(adapter); 
    Assert.assertTrue(products.size() == 3); 
} 

Así que para poner a prueba mi adaptador, tengo que crear un nuevo adaptador y una nueva fuente de datos. Realmente no me importa la fuente de datos, solo necesito asegurarme de que mi adaptador haga lo que tenía previsto que hiciera. Mocking me permite probar mi adaptador de forma aislada al especificar el tipo de interfaz y configurar cómo quiero que se comporte. Ahora no estoy atada a una implementación de clase concreta para probar mi adaptador.

Así que aquí es un ejemplo, donde uso JMock para crear un origen de datos simulada:

@Test 
public void MockingTest() { 

    final Mockery context = new Mockery(); 

    final List<Product> mockData = new ArrayList<Product>(); 
    mockData.add(new Product("Sample Product 1")); 
    mockData.add(new Product("Sample Product 2")); 
    mockData.add(new Product("Sample Product 3")); 

    final IProductsDatasource mockDatasource = context.mock(IProductsDatasource.class); 

    context.checking(new Expectations(){{ 
     oneOf (mockDatasource).getProducts(); will(returnValue(mockData)); // This is where I tell JMock to return my test data when getProducts() is called 
    }}); 

    TargetAdapter adapter = new TargetAdapter(mockDatasource); // No dependency ;) 
    List<Product> products = adapter.products(); 

    Assert.assertNotNull(adapter); 
    Assert.assertTrue(products.size() == 3); 

} 

Desde que declaró que eran nuevas para las pruebas unitarias, quería señalar el poder de los objetos de imitación en las pruebas unitarias y cómo puede aprovecharlos para escribir un mejor código. También puede configurar objetos simulados para asegurarse de que su objeto objetivo invoque un método en su simulacro. Lo uso mucho cuando no estoy interesado en la implementación de un método o el resultado, solo quiero asegurarme de que mi clase lo llame cuando debería. Ahora para hacer todo este trabajo, usted tiene que utilizar las interfaces pero es bastante fácil simplemente hacer una refactor -> interfaz de extracto de

me encontré con todo esto en Eclipse antes de lo publicado por lo que el código funciona si quieres jugar alrededor con eso. ¡Espero que esto ayude!

Cuestiones relacionadas