Avatar billede dl Nybegynder
10. september 2007 - 23:10 Der er 17 kommentarer og
1 løsning

JUnit på en persistens mapper

Jeg har en persistensfacade, dens formål er at finde ud af hvilken mapper der skal bruges til at persister en alm. pojo.

Den virker, det kan jeg konstatere, ved at køre det og ser hvad der sker.

Men nu er det jo sådan, så det er min hovedopgave som datamatikker, og jeg og min gruppe ville meget gerne have Junit ind over, gerne med Jmock 1.2.

Problemmet er bare, at vi på skolen ikke har lært så meget om Junit, og vi kan ikke lige se, hvordan vi skal teste en mapper, hvor vi jo skal i DB og i en Identety mapper.

// kode snip //
package framework;

import domaene.Postnr;
import framework.interfaces.MapperInterface;
import framework.interfaces.PersistensFacadeInterface;
import framework.mapper.PostnrMapper;
import java.util.HashMap;

public class PersistensFacade implements PersistensFacadeInterface {
   
    private static PersistensFacade instance;
    private HashMap mapper;
   
    public PersistensFacade() {
        mapper = new HashMap();
        addMapper( Postnr.class, new PostnrMapper() );
    }
   
    public void addMapper( Class aClass, Object o ) {
        String mapperNavn = aClass.toString();
        mapper.put( mapperNavn , o );
    }
   
    public static PersistensFacade getInstance() {
        if (instance == null)
            instance = new PersistensFacade();
        return instance;
    }

    public Object get(int id, Class aClass) throws Exception {
      MapperInterface map = null;
      if (mapper.containsKey(aClass.toString()))
            map = ((MapperInterface)mapper.get(aClass.toString()));
        return map.get(id);
    }

    public void put(int id, Object o) throws Exception {
        MapperInterface map = null;
       
        Class aClass = o.getClass();
        if (mapper.containsKey(aClass.toString()))
            map = ((MapperInterface)mapper.get(o.getClass().toString()));
            map.put(id, o);       
    }

}


// kode snip //

package framework.mapper;

import database.DBModul;
import domaene.Postnr;
import exception.database.DBException;
import framework.interfaces.MapperInterface;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;

public class PostnrMapper implements MapperInterface {
   
    private HashMap map;
   
    public PostnrMapper() {
        map = new HashMap();
    }
   
    public boolean idFindesIdatabase(int id) throws Exception {
        try {
            ResultSet rs = DBModul.getInstance().executeQuery("SELECT count(postnr) FROM Postnr WHERE postnr = " + id);
            rs.next();
            if (rs.getInt(1) == 1)
                return true;
            else
                return false;
        } catch (SQLException ex) {
            throw new Exception("fejl !! i postnr mapper.");
        }
    }
   
    public boolean idFindesImap(int id)
    {
        return map.containsKey(new Integer(id));
    }
   
    public Object hentPostnrFraDB(int id) throws Exception {
        try {
            ResultSet rs = DBModul.getInstance().executeQuery("SELECT * FROM Postnr WHERE postnr = " + id);
            rs.next();
   
            Postnr p = new Postnr();
            p.setPostNr(rs.getInt("postnr"));
            p.setBynavn(rs.getString("bynavn"));
           
            return p;
        } catch (SQLException ex) {
            throw new Exception("Postnr findes ikke i DB.");
        }
    }
   
    public Object get(int id) throws Exception {
        if (idFindesImap(id)) {
            System.out.println("PostnrMapper: Henter Postnr fra HashMap");
            return map.get(new Integer(id));
        }
        else
        {
            System.out.println("PostnrMapper: Henter Postnr fra Database");
            Object obj = hentPostnrFraDB(id);
            map.put(new Integer(id), obj);
            return obj;
        }
    }
       

    public void OpretInDB(Object o ) throws Exception {
        Postnr p = ((Postnr)o);
        DBModul.getInstance().setAutoCommit(false);
        DBModul.getInstance().executeUpdate("INSERT INTO Postnr (postnr, bynavn) VALUES (" + p.getPostNr() + ", '" + p.getBynavn() + "')");               
        DBModul.getInstance().commit();

    }
   
    public void updateInDB(Object o) throws Exception {
                Postnr p = ((Postnr)o);
                DBModul.getInstance().setAutoCommit(false);
                DBModul.getInstance().executeUpdate("UPDATE Postnr SET bynavn = '" + p.getBynavn() + "' WHERE postnr = " + p.getPostNr());
                System.err.println("PostnrMapper: UPDATE Postnr SET bynavn = '" + p.getBynavn() + "' WHERE postnr = " + p.getPostNr());
                DBModul.getInstance().commit();
    }
       
   
    public void put(int id, Object o) throws Exception {
          Postnr p = ((Postnr)o);
          map.remove(new Integer(id));
          if (!idFindesIdatabase(id)) {
                System.out.println("PostnrMapper:  Opret Postnr i Database.");
                OpretInDB(o);
          } else {
                System.out.println("PostnrMapper: Update Postnr i Database.");
                updateInDB(o);
                map.put(new Integer(id), o);
          }
    }
   
}





Dette er bare med et alm postnr, som vi kender det, og den skal så igemmen persistenFacade, persistensfacade finder ud af, hvilken mapper, som skal bruges og sender det vidre.

Alle Mapper har et  interface: som har get og put metoder i, så vi kan bruge polymorfi.

Jeg sætter denne opgave som svær, da jeg ikke har nogle ide til hordan man teste dette problem.

For lige at opsumere:

1) lave Junit test til PersistensFacade
2) meget gerne junit test til en mapper også.

Jeg håber at der kommer nogle gode forslag. Eftersom jeg ved at der er nogle ret gode folk herinde.

// DL
Avatar billede arne_v Ekspert
11. september 2007 - 02:40 #1
Jeg kan ikke se problemet i at unit teste de klasser med JUnit.

Du kan teste en mapper ved at lave et kald og så checke med manuelle JDBC kald.

Du kan teste din persistens facade på samme måde eller med en speciel mockup mapper.
Avatar billede arne_v Ekspert
11. september 2007 - 02:45 #2
Et udsnit af noget kode jeg havde på lageret:

    public void test2Find() {
        try {
            Context ctx = new InitialContext();
            Object temp = ctx.lookup("People");
            PeopleHome home = (PeopleHome) temp;
            assertNotNull("home", home);
            People p1 = home.findByPrimaryKey(new Integer(1));
            assertNotNull("bean", p1);
            assertEquals("Peopleid", new Integer(1), p1.getPeopleid());
            assertEquals("Firstname", "A", p1.getFirstname());
            assertEquals("Lastname", "AA", p1.getLastname());
            assertEquals("Address1", "A road 1", p1.getAddress1());
            assertEquals("Address2", "-", p1.getAddress2());
            assertEquals("Zipcode", "1234", p1.getZipcode());
            assertEquals("City", "A town", p1.getCity());
            assertEquals("Country", "Denmark", p1.getCountry());
            assertEquals("Workphone", "11111111", p1.getWorkphone());
            assertEquals("Homephone", "22222222", p1.getHomephone());
            assertEquals("Mobilephone", "33333333", p1.getMobilephone());
            assertEquals("Workfax", "44444444", p1.getWorkfax());
            assertEquals("Homefax", "55555555", p1.getHomefax());
            assertEquals("Workemail", "a@a.com", p1.getWorkemail());
            assertEquals("Privateemail1", "a@a.dk", p1.getPrivateemail1());
            assertEquals("Privateemail2", "-", p1.getPrivateemail2());
            assertEquals("Privateemail3", "-", p1.getPrivateemail3());
            People p2 = home.findByPrimaryKey(new Integer(2));
            assertNotNull("bean", p2);
            assertEquals("Peopleid", new Integer(2), p2.getPeopleid());
            assertEquals("Firstname", "B", p2.getFirstname());
            assertEquals("Lastname", "BB", p2.getLastname());
            assertEquals("Address1", "B road 2", p2.getAddress1());
            assertEquals("Address2", "-", p2.getAddress2());
            assertEquals("Zipcode", "1234", p2.getZipcode());
            assertEquals("City", "B town", p2.getCity());
            assertEquals("Country", "Denmark", p2.getCountry());
            assertEquals("Workphone", "66666666", p2.getWorkphone());
            assertEquals("Homephone", "77777777", p2.getHomephone());
            assertEquals("Mobilephone", "88888888", p2.getMobilephone());
            assertEquals("Workfax", "-", p2.getWorkfax());
            assertEquals("Homefax", "-", p2.getHomefax());
            assertEquals("Workemail", "b@b.com", p2.getWorkemail());
            assertEquals("Privateemail1", "b@b.dk", p2.getPrivateemail1());
            assertEquals("Privateemail2", "-", p2.getPrivateemail2());
            assertEquals("Privateemail3", "-", p2.getPrivateemail3());
            People p3 = null;
            try {
                p3 = home.findByPrimaryKey(new Integer(3));
                fail("FinderException should be thrown");
            } catch (FinderException ex1) {
                // nothing
            }
            assertNull("bean", p3);
            Collection colall = home.findAll();
            Iterator itall = colall.iterator();
            int nall = 0;
            while(itall.hasNext()) {
                People p = (People)itall.next();
                assertNotNull("bean", p);
                nall++;
            }
            assertEquals("find all", 2, nall);
            Collection colfirstname = home.findByFirstname("A");
            Iterator itfirstname = colfirstname.iterator();
            int nfirstname = 0;
            while(itfirstname.hasNext()) {
                People p = (People)itfirstname.next();
                assertNotNull("bean", p);
                nfirstname++;
            }
            assertEquals("find firstname", 1, nfirstname);
            Collection collastname = home.findByLastname("A%");
            Iterator itlastname = collastname.iterator();
            int nlastname = 0;
            while(itlastname.hasNext()) {
                People p = (People)itlastname.next();
                assertNotNull("bean", p);
                nlastname++;
            }
            assertEquals("find lastname", 1, nlastname);
            Collection colphone = home.findByPhone("11111111");
            Iterator itphone = colphone.iterator();
            int nphone = 0;
            while(itphone.hasNext()) {
                People p = (People)itphone.next();
                assertNotNull("bean", p);
                nphone++;
            }
            assertEquals("find phone", 1, nphone);
            Collection colemail = home.findByEmail("a@a.dk");
            Iterator itemail = colemail.iterator();
            int nemail = 0;
            while(itemail.hasNext()) {
                People p = (People)itemail.next();
                assertNotNull("bean", p);
                nemail++;
            }
            assertEquals("find email", 1, nemail);
        } catch (FinderException ex) {
            fail(ex.getMessage());
        } catch (NamingException ex) {
            fail(ex.getMessage());
        }
    }

(der er sat nogle kendte data op på forhånd)
Avatar billede arne_v Ekspert
11. september 2007 - 02:46 #3
PS: der er et par andre ting som falde mig meget i øjnene med din kode ...
Avatar billede dl Nybegynder
11. september 2007 - 08:17 #4
Jeg ser gerne du skriver alle dine "ting som falder dig for"  :) det kunne jo være nogle guldkorn, du tabte. ;)

/// dennis
Avatar billede dl Nybegynder
11. september 2007 - 15:34 #5
Tak skal du have med inspiration, har vi lavet det hele om, samt at det bare køre derud af med test, så det må jo betyde at vi er på rette spor.

// dennis

Arne_v kom med et svar. det må man sige er på sin plads :)
Men jeg vil meget gerne have nogle guldkorn, hvis det er sådan så du lige vil skrive 2 linie... hvad dine tanker er.
Avatar billede arne_v Ekspert
11. september 2007 - 17:09 #6
Din PersistensFacade klasse ligner en singleton, men du har en public constructor.
Avatar billede arne_v Ekspert
11. september 2007 - 17:10 #7
I din get og put vil en ikke registereret klasse give en NullPointerException.
Avatar billede arne_v Ekspert
11. september 2007 - 17:12 #8
Du bruger ikke PreparedStatement.
Avatar billede arne_v Ekspert
11. september 2007 - 17:13 #9
Du boer broge log4j eller java.util.logging fremfor System.out.println.
Avatar billede arne_v Ekspert
11. september 2007 - 17:14 #10
Jeg tvivler paa at DBModul er thread safe.
Avatar billede arne_v Ekspert
11. september 2007 - 17:15 #11
PostnrMapper.put er ikke flerbruger sikker.
Avatar billede dl Nybegynder
11. september 2007 - 17:16 #12
DBModul, har du helt ret i :)
Vores persistensFacade, er slettet, den var vores store problem, og derfor vil vi nu tage det i vores kontroller klasser.

PreparedStatement: vores mapper tager sig er det, så vi behøver det ikke .. man jo, overblik :)
Avatar billede dl Nybegynder
11. september 2007 - 17:18 #13
Kom bare med et svar ... da vi har lavet en del af vores konstruktion om :)  Så derfor passer den overstpende kode ikke mere.

Men jeg skal da lige holde nogle at de ting du kommer med, i en lille note.

// dennis

men tak for hjælpen, en god inspiretion  :)
Avatar billede arne_v Ekspert
11. september 2007 - 17:20 #14
Og et svar.
Avatar billede fsconsult.dk Nybegynder
12. september 2007 - 07:50 #15
ved PreparedStatement er det en RIGTIG god ide, da den udover at gøre tingene lettere, er med til at modvirke sql-injection og quotes i tekstfelter.
Avatar billede dl Nybegynder
12. september 2007 - 08:31 #16
"sql-injection og quotes i tekstfelter" vil du ikke lige være sød at uddybe det engang ?
Avatar billede fsconsult.dk Nybegynder
12. september 2007 - 08:41 #17
SQL injection vil sige at de kan tilføje noget til dit SQL statement, der kan betyde at din database bliver slettet, eller lignende ting ved f.eks. at tilføje quotes (" eller ') i tekstfelter, samt yderligere sql kommandoer.

Quotes kan generelt være et stort problem, hvis din sql hedder "update tabel set feltnavn='" + feltværdi +"'", og så feltværdi er feks "Jens Hansens' bondegård", så vil din SQL fejle, medmindre din mapper håndterer det i 100% af de mulige kombinationer.
Avatar billede dl Nybegynder
12. september 2007 - 12:33 #18
I see :)

det vil jeg da lige tage op med min gruppe :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester