Gerador de dados Fake

Bom dia à todos !

Sei que pode parecer estranho este tipo de necessidade, mas eu preciso de um gerador de dados
fake,
para ser mais específico, preciso de uma classe utilitaria com um metodo
para o qual eu passe um bean e ela se encarregue de preencher todos os membros do meu bean
e todos os membros dos beans que são membros do primeiro bean recursivamente com dados
aleatórios.
Se alguém souber de algo que faça isso, realmente iria me ajudar demaaais !
Valeu gente !!

Já precisei disso um dia so bad. Até hoje n vi nada que se adequasse.

Opa… q interessante sua pergunta, é muito util… sem isso perdemos muito tempo.

Ótima Pergunta… amigo

Deixa eu ver se entendi.
vc quer uma classe que popule seus dados para testes?
vc poderia criar uma classe q sempre setasse os valores, o problema é q para cada caso teria q ter uma classe Fake só para setar esses dados. :smiley:

Seguindo a lógica do cara aí de cima poderia ser feito usando reflection. Vc pega os “declaredFields” de um object qualquer, vê o tipo de dados deles, gera um valor aleatório e joga lá dentro.

Eu faço mais ou menos assim. Se você tem um UsuarioDAO e uma implementação UsuarioMySQLDAO, cria um UsuarioInMemoryDAO. Este por sua vez salva em memória usando java.util.Map. Depois crie uma classe que popula o DAO. Não é tão trabalhoso. Você pode usar estratégias (pattern Strategy) para gerar os Id’s e até mesmo criar um DAO genérico para persistir em memória.

olha… jah passei pro um problema parecido pra testar algumas classes…
precisava de uma tabela MySQL bem preenchida…

no caso eram apenas o ID (automatico), uma string e um inteiro…

entao eu criei uma classe q executou um loop 1000x com comandos de Insert pro BD…

o int era randomico… entre 1 e 100…
e pra gerar a string q foi o problema… entao acabei criando uma array de 10 strings, e sorteava 1 numero de 1-10 para escolher qual delas seria inserida na linha…

será q nao eh possivel fazer nada parecido?

Eu já implementei uma solução assim, funcionou mto bem no meu caso…

Vou postar o código, foi criado para uma necessidade específica aqui, adeque de acordo com a sua necessidade…

Já adiantando que rodei isso no Java 5…

[code]package com.sistema.tests;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import com.maestro.persistence.exception.EntityFinderException;

/**

  • Classe para teste e log reflexivo dos métodos finder das classes Entity

  • @author Cláudio Loureiro

  • @version 27/06/2008
    */
    public class EntitiesFindersTest {

    private static final String PACKAGE = “com.sistema.persistence.entity”;

    private static final String[] HOME_CLASS_NAMES = {
    “Classe1Home”, // Omiti os nomes reais que são sigilosos
    “Classe2Home”,
    };

    private static final Map<String, Object> ARGS = loadArgs();

    private static final Pattern FINDER_PATTERN = Pattern.compile("^find.*$");

// private static final Pattern GETTER_PATTERN = Pattern.compile("^get.*$");

private static final Pattern ID_PATTERN = Pattern.compile("^.*Id$");

private static final Pattern TYPE_PATTERN = Pattern.compile("^.*Type$");

public EntitiesFindersTest(){
try {
    testFinders();
} catch (Exception e) {
    e.printStackTrace();
}
}

private void testFinders() throws Exception {
for(String className : HOME_CLASS_NAMES){
    Class<?> c = Class.forName(PACKAGE+"."+className);
    Object obj = c.newInstance();
    System.out.println("---------- ---------- ----------\nEntity:\t"+c.getSimpleName()+"\nFinders:");
    Method[] methods = c.getMethods();
    for(Method method : methods){
	if(!FINDER_PATTERN.matcher(method.getName()).matches())continue;
	Object[] parameters = prepareArgs(method.getParameterTypes());
	showFinderLog(method, parameters);
	try{
	    method.invoke(obj, parameters);
	} catch(InvocationTargetException e) {
	    treatInvocationTargetException(e);
	}
    }
}
}

private Object[] prepareArgs(Class<?>[] parameterTypes) throws Exception {
if(parameterTypes==null || !(parameterTypes.length>0))return null;
Object[] args = new Object[parameterTypes.length];
for(int i=0; i<args.length; i++){
    Object obj = null;
    if(ID_PATTERN.matcher(parameterTypes[i].getSimpleName()).matches()){
	obj = parameterTypes[i].newInstance();
	Field[] fields = parameterTypes[i].getDeclaredFields();
	for(int j=0; j<fields.length; j++){
	    fields[j].setAccessible(true);
	    fields[j].set(obj, ARGS.get(fields[j].getType().getSimpleName()));
	}
    } else if(TYPE_PATTERN.matcher(parameterTypes[i].getSimpleName()).matches()){
	obj = parameterTypes[i].getConstructor(new Class[]{String.class}).newInstance(new Object[]{ARGS.get("StringCode")});
    } else {
	obj = ARGS.get(parameterTypes[i].getSimpleName());
    }
    args[i] = obj;
}
return args;
}

private void showFinderLog(Method method, Object[] parameters) {
System.out.print("\t--- "+method.getName()+"(");
Class<?>[] parameterTypes = method.getParameterTypes();
for(int i=0; i<parameterTypes.length; i++){
    System.out.print(parameterTypes[i].getSimpleName()+(i<parameterTypes.length-1?", ":""));
}
System.out.print(")(");
for(int i=0; parameters!=null && i<parameters.length; i++){
    String parameter = parameters[i]==null?null:ID_PATTERN.matcher(parameters[i].getClass().getSimpleName()).matches()?"id_obj":TYPE_PATTERN.matcher(parameters[i].getClass().getSimpleName()).matches()?"type_obj":parameters[i].toString();
    System.out.print(parameter+(i<parameters.length-1?", ":""));
}
System.out.println(") ---");
}

private void treatInvocationTargetException(InvocationTargetException e) throws Exception {
    boolean isEntityFinderException = false;
    Throwable t = e;
    while(t!=null) {
        if(t instanceof EntityFinderException) {
            isEntityFinderException = true;
            System.out.println("EntityFinderException - ok");
            break;
        }
        t = t.getCause();
    }
    if(!isEntityFinderException){
        // Eu não preciso da InvocationTargetException, mas da sua causa
        throw (Exception)e.getCause();
    }
}

/**
 * @param args
 */
public static void main(String[] args) {
new EntitiesFindersTest();
}

private static Map<String, Object> loadArgs() {
Map<String, Object> map = new HashMap<String, Object>();

map.put("StringCode", "01");
map.put("String", "Teste");
map.put("Integer", 1);
map.put("int", 1);
map.put("Long", 1L);
map.put("long", 1L);
map.put("Byte", (byte)1);
map.put("byte", (byte)1);
map.put("Float", 1.0F);
map.put("float", 1.0F);
map.put("Double", 1.0);
map.put("double", 1.0);
map.put("BigDecimal", new BigDecimal(1.0));
map.put("Date", new java.util.Date());

return map;
}

}[/code]

Valeu a todos pelas respostas,

No caso o que eu estou precisando mesmo eh algo bem generico,
vou passar um bean e o meu metodo vai preencher todos os campos dentro do bean com
valores randomicoes ou padroes como :

para String, preencher com (“Joao_” + ((int)(Math.random()*1000)) )
para Integer, preenhcer com ((int)(Math.random()*1000))

e assim por diante, se encontrasse um outro bean dentro deste bean,
chamaria novamente esta funcao com esse bean no parametro e assim vai, recursivamente. Se encontrar
uma collection, (isso nao eh muito, hmm … digamos … elegante) vai pegar o tipo do primeiro cara da collection, e subentendendo
que a collection so vai ter classes desse tipo, se elas forem beans, chama a mesma funcao para cada um dos beans da collection …

No caso, a solucao que mais se encaixa eh a do Fox (by the way, love that game)
porem preciso que seja java 1.4, pois o projeto em questao eh
java 1.4 …

nao eh tao dificil de fazer nao, estou fazendo aqui com java 1.4, assim que tiver terminado vou postar aqui no
guj a solucao encontrada.

Valeu gente !!!

/**
 * Created on 14/07/200815:37:32 
 * FakeGenerator.java
 */
package br.com.emmanuel.santana.application;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;

/**
 * @author emmanuel.santana, ednilson.sobrinho
 * @version 1.0
 *
 */
public class FakeGenerator {
	private static HashMap typeValues = new HashMap();
	
	static {
		typeValues.put("String", "teste");
		typeValues.put("Integer", new Integer(2));
		typeValues.put("Short", new Short((short)2));
		typeValues.put("Long", new Long(2));
		typeValues.put("Date", new Date());
	}
	
	/**
	 * Preenche todos os campos configurados no map com valores fake para teste.
	 * Não preenhce Collection por ser java 1.4 e não foi ainda configurada para preencher campos
	 * primitivos, pois estes já são setadas com o valor padrão
	 * 
	 * @param obj
	 */
	public static void fillBean(Object obj) {
		try {
			Method [] methods = obj.getClass().getDeclaredMethods();
			Field [] fields = obj.getClass().getDeclaredFields();
			
			
			for (int i = 0; i < methods.length; i++) {
				
				if(methods[i].getName().substring(0, 3).equals("set")){
					// field name pego da assinatura do metodo
					String fieldName = (methods[i].getName().substring(3,4)).toLowerCase()+methods[i].getName().substring(4);
					
					for (int j = 0; j < fields.length; j++) {
						// acessar todos os campos
						Field field = fields[j];
						
						if(!field.getType().isPrimitive()) {
							String name = field.getType().getName();
							String type = name.substring(name.lastIndexOf(".")+1);
							// verificar se o metodo pego acima eh o SET de algum dos campos
							if(field.getName().equals(fieldName)){
								System.out.println(fieldName);
								// acessar o mapa para ver que valor atribuir
								Object value = typeValues.get(type);

								if(value == null) {
									// instanciar o objeto e chamar esta mesma funcao recursivamente
									try {
										value = Class.forName(name).newInstance();
										fillBean(value);
									} catch (Exception e) {}
								}
								methods[i].invoke(obj, new Object[]{value});
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Este é um teste da nossa funcionalidade
	 * @param args
	 */
//	public static void main(String[] args) {
//		Pessoa pessoa = new Pessoa();
//		fillBean(pessoa);
//		System.out.println(pessoa);
//	}
}

Pronto,
era mais ou menos isso que eu estava precisando,
fiz junto com um colega meu aqui do trabalho.

Estamos usando java 1.4 por isso criar fake Collections nao
seria possivel de maneira, digamos … elegante …

Testei com um bean que criei aqui, se puderem,
por favor testem ai tambem.

Para mim serviu muito bem.

Valeu gente, Falows !!
:wink:

Ahh … gente,
não esquecendo agradecimentos especiais ao Bob Perillo (RobertoGeller) aqui do Forum, que me passou alguns bons princípios de reflection ontem.

Abraço à todos !

pelo que vejo estas classes geram qualquer tipo de dados dependendo do tipo… porem para algo mais sofisticado e com validações é algo mais trabalhoso… para testar as validações… exemplo cpf ou cnpj tem um algoritimo de digito verificador… cep tem um esquema de validação… o interessante seria criar uma classe de teste utilitaria que pegasse campos como cnpj/cep e campos de validações e implementasse uma arvore de eventos de teste… mas é algo bem chatinho de se fazer…

Fala Manu!
Eu tava vendo aqui seu código, ficou muito bom! Eu falei ontem pra vc q o céu o limite e vc levou a sério hein! :slight_smile:
Bom, só umas dicas de boas práticas: referencie o HashMap com Map, e use o startsWith ao invés substring.
Mas ficou show, man. Congrats!

Então, a intensão inicial era adaptar o código à nossa necessidade aqui na empresa.
Porém o algoritmo pode ser muito melhorado, e é claro, pode-se colocar outros tipos de validação como vc mesmo citou, porém isso vai ficar para a proxima versão, por enquanto esse ai está nos sendo bem útil.
Quando tiver um tempo, vou tentar fazer um legal usando java 5.

Valeu pelas dicas Bob !