Länge eines Arrays in einem Objekt testen

nikva

Bekanntes Mitglied
Hallo Java-Forum!
Ich sitze grade an einer Programmieraufgabe zum Thema Vererbung,Arrays und jUnit Tests.
An diesem jUnit Test hänge ich aber grade etwas fest(die Vorlesung dazu fiel aufgrund der Corona-Situation aus)

Ich versuche den tatsächlichen Wert in die AssertEquals Methode einzubauen aber der compiler erkennt den Typ nicht.
Im Anhang befindet sich die Aufgabenstellung und nachfolgend die Klassen.
Hoffe mir kann hier jemand weiterhelfen :)

Java:
package edu.hm.cs.swe2.shoppingmall;

public class ShoppingMall {

    public Shop[] shops;

    public ShoppingMall(int shopCount) {
        if (shopCount < 1 || shopCount > 500) {
            shopCount = 10;
        } else {
            this.shops = new Shop[shopCount];
        }
    }

    public int addShops(Shop... shopsToAdd) {
        int currentnumber = 0;
        int notPlacable = 0;
        for (Shop shop : shopsToAdd) {
            if (this.shops.length <= currentnumber + 1 && this.shops[currentnumber] != null) {
                this.shops[currentnumber] = shop;
            } else {
                notPlacable++;
            }
            currentnumber++;
        }
        return notPlacable;
    }

    public float calculateRent() {
        float totalRent = 0;

        return totalRent;
    }
}
Java:
package edu.hm.cs.swe2.shoppingmall;

import java.time.LocalDateTime;

public class Shop {

    private int area;
    private String name;
    private int rent;
    private LocalDateTime openingTime;
    private LocalDateTime closingTime;

    private Shop(int area, String name, int rent) {

    }

    public String toString() {
        return String.format("name: %s area: %s rent: %s", name, area, rent);
    }

    public int getArea() {
        return this.area;
    }

    public void setArea(int area) {
        this.area = area;
    }

    public int getRent() {
        return this.rent;
    }

    public void setRrea(int area) {
        this.area = area;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
Java:
package edu.hm.cs.swe2.shoppingmall;

public class SecurityCountable {
    int personCount;

    void addPerson() {
        personCount = personCount + 1;

    }

    void removePerson() {
        personCount = personCount - 1;
    }

    int showPersonCount() {
        return personCount;
    }

    // Methode die einen Alarm ausgibt
}
Java:
package edu.hm.cs.swe2.shoppingmall;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

class ShoppingMallTest {

    @Test
    void TestShoppingMall() {
        int shopCountTest = 0;
        ShoppingMall TestShoppingMall = new ShoppingMall(shopCountTest);
        int expectedResult = 10;
        int actualResult = 0;

        assertEquals(expectedResult, ShoppingMall(0));
    }
}
 

Anhänge

  • A01-Shopping-Mall(1).pdf
    214,7 KB · Aufrufe: 7

httpdigest

Top Contributor
Ja, vielen Dank für die Aufgabe.
Aber: Wobei können wir dir denn hier helfen? Wo hast du noch Probleme? Was fehlt dir, um die Aufgabe selbst lösen zu können? Warum sollte jemand überhaupt die 5 PDF Seiten voll mit Aufgaben und Unteraufgaben lesen, ohne überhaupt zu wissen, was das genaue Problem ist?
 

nikva

Bekanntes Mitglied
Mein Problem ist wie gesagt das Testen der Klasse ShoppingMall durch einen JUnit Test(ShoppingMallTest). Ich scheitere grade daran den tatsächlichen Wert mit dem erwarteten Wert zu vergleichen
Die Aufgabe um die es geht ist Aufgabe 4 d)
 

nikva

Bekanntes Mitglied
Aber ich will ja hier keine Arrays miteinander vergleichen sondern die Länge zweier Arrays miteinander vergleichen.
Das Array aus ShoppingMall mit dem Paramater 0 soll zum Beispiel ein Array der Länge 10 ausgeben
 

temi

Top Contributor
ShoppingMall ist eine Klasse. Was ShoppingMall(0) bewirken soll, erschließt sich mir nicht.

Vielleicht möchtest du ja was mit der Instanz dieser Klasse anstellen ShoppingMall TestShoppingMall = new ShoppingMall(shopCountTest);?

Nebenbei: Variablen werden in Java konventionsgemäß mit einem Kleinbuchstaben am Anfang geschrieben.

Wenn du die Länge eines Arrays brauchst, dann erhältst du die mit array.length, allerdings nur die definierte Länge, nicht die tatsächliche.
 
Zuletzt bearbeitet:

nikva

Bekanntes Mitglied
Java:
public class ShoppingMall {

    public Shop[] shops;

    public ShoppingMall(int shopCount) {
        if (shopCount < 1 || shopCount > 500) {
            shopCount = 10;
        } else {
            this.shops = new Shop[shopCount];
        }
    }
Hiermit soll ja immer ein Array erstellt werden mit einer Länge die die Anzahl der shops beschreibt mit Standartwert 10 falls er nicht zwischen 1 und 500 liegt

Java:
    @Test
    public void TestShoppingMall() {
        int shopCountTest = 0;
        ShoppingMall TestShoppingMall = new ShoppingMall(shopCountTest);
        int expectedResult = 10;
        int actualResult = // hier soll jetzt der vergleichswert hin der in SHoppingMall mit 0 als Parameter entsteht
        assertEquals(expectedResult, actualResult);
    }
}
 

temi

Top Contributor
Steht inzwischen alles schon hier in den Beiträgen.

Edit: Oder ist die Frage, wie du auf das Feld "shops" der Instanzvariablen zugreifen kannst?

Das geht mit TestShoppingMall.shops. Die Variable sollte allerdings, wie schon geschrieben, besser "testShoppingMall" heißen.
 
Zuletzt bearbeitet:

httpdigest

Top Contributor
Java:
public ShoppingMall(int shopCount) {
    if (shopCount < 1 || shopCount > 500) {
        shopCount = 10;
    } else {
        this.shops = new Shop[shopCount];
    }
}
Hiermit soll ja immer ein Array erstellt werden mit einer Länge die die Anzahl der shops beschreibt mit Standartwert 10 falls er nicht zwischen 1 und 500 liegt
Dann teste diesen Konstruktor mal gut. Wenn die Tests gut sind, werden sie da noch einen Fehler feststellen. :)
 

nikva

Bekanntes Mitglied
Java:
public class ShoppingMallTest {

    @Test
    public void TestShoppingMall() {
        int shopCountTest = 0;
        ShoppingMall testShoppingMall = new ShoppingMall(shopCountTest);
        int expectedResult = 10;
        int actualResult = testShoppingMall.length;
        assertEquals(expectedResult, actualResult);
    }
}

Jetzt kriege ich die Meldung "length cannot be resolved or is not a field", die ich beheben kann indem ich eine Variable "length in ShoppingMall erzeuge. Dies ist aber genau das was ich ja nicht will.
 

nikva

Bekanntes Mitglied
Vielleicht stell ich mir das ganze auch ganz falsch vor.
Zuerst erstelle ich die Testmethode, dann lege ich einen Testwert fest der als Parameter für den Kontruktor der Klasse ShoppingMall dient. Danach lege ich einen erwarten Wert fest und vergleiche den Wert über die AssertEquals Methode mit dem Ergebnis aus dem Konstruktor der ShoppingMall. Wenn ich jetzt aber versuche nach dem erstellen der Beispiel-ShoppingMall die Länge aufzurufen kommt die Fehlermeldung "length cannot be resolved or is not a field. Es tut mir Leid wenn ich euch hier nerve aber ich komme einfach nicht dahinter wo der Fehler liegt. Anscheinend erzeugt meine Testmethode ja kein Testarray, dass ich vergleichen kann? Ich habe es auch mit einem Array als expected Result probiert(Shop[] expectedResult = Shop[10] und dann mit AssertArrayequals zu vergleichen

Java:
package edu.hm.cs.swe2.shoppingmall;

import org.junit.jupiter.api.Test;

public class ShoppingMallTest {


    @Test
    public void testShoppingMall() {
        int shopCountTest = 0;
        // Testwert bestimmen
        ShoppingMall testShoppingMall = new ShoppingMall(shopCountTest);
        // erzeugt ein Objekt ShoppingMall mit Testwert
        int expectedResult = 10;
        // zu erwartender Array der durch Shoppingmal erzeugt wird mit Testwert 0
        int actualResult = testShoppingMall.length; //cannot be resolved or is not a field
    }

}

Java:
package edu.hm.cs.swe2.shoppingmall;

public class ShoppingMall {

    public Shop[] shops;

    public ShoppingMall(int shopCount) {
        if (shopCount < 1 || shopCount > 500) {
            shopCount = 10;
        } else {
            this.shops = new Shop[shopCount];
        }
    }

    public int addShops(Shop... shopsToAdd) {
        int currentnumber = 0;
        int notPlacable = 0;

        for (Shop shop : shopsToAdd) {
            if (this.shops.length <= currentnumber + 1 && this.shops[currentnumber] != null) {
                this.shops[currentnumber] = shop;
            } else {
                notPlacable++;
            }
            currentnumber++;
        }
        return notPlacable;
    }

    public float calculateRent() {
        float totalRent = 0;

        return totalRent;
    }
}
 

httpdigest

Top Contributor
Java:
        ShoppingMall testShoppingMall = new ShoppingMall(shopCountTest);
        // erzeugt ein Objekt ShoppingMall mit Testwert
        int expectedResult = 10;
        // zu erwartender Array der durch Shoppingmal erzeugt wird mit Testwert 0
        int actualResult = testShoppingMall.length; //cannot be resolved or is not a field
Überlege doch mal bitte, was du hier machst... `testShoppingMall` bzw. ein ShoppingMall selbst hat doch kein `length` Attribut.... die `shops` Instanzvariable in einem `ShoppingMall` hat length.
 

mihe7

Top Contributor
length ist ein Attribut eines Arrays. Du hast aber ein Objekt vom Typ Shoppingmall. Wenn Du die Länge des shops-Arrays abrufen willst, spendierst Du der Klasse eine Methode und verwendest diese, z. B.
Java:
public int size() {
    return shops.length;
}
 

nikva

Bekanntes Mitglied
Java:
package edu.hm.cs.swe2.shoppingmall;

import org.junit.jupiter.api.Test;

public class ShoppingMallTest {

    @Test
    public void testShoppingMall() {
        int shopCountTest = 0;
        // Testwert bestimmen
        ShoppingMall testShoppingMall = new ShoppingMall(shopCountTest);
        // erzeugt ein Objekt ShoppingMall mit Testwert
        int expectedResult = 10;
        // zu erwartende Länge des Array der durch Shoppingmal erzeugt wird mit Testwert
        // 0

        assertEquals(expectedResult, shops.size());// shops cannot be resolved
    }

}
auch über die Methode funktioniert es in meiner Testmethode nicht. Stimmt denn überhaupt der generelle Ansatz oder bin ich komplett auf dem Holzweg?
 
K

kneitzel

Gast
Wenn Du diese Größe von außen prüfen willst, dann musst Du diese von Außen zugreifbar machen. Das ist das, was mihe7 ja bereits auch so beschrieben hat.
 

temi

Top Contributor
Ich glaube du verstehst nicht, worauf wir hinaus wollen:
Java:
ShoppingMall testShoppingMall = new ShoppingMall(shopCountTest); // deine Instanz von ShoppingMall

// entweder du greifst direkt auf das Attribut zu
int actualResult = testShoppingMall.shops.length;

// oder über eine Methode, wie von mihe7 vorgeschlagen
int actualResult = testShoppingMall.size();

Die zweite Möglichkeit ist die bessere.
 

nikva

Bekanntes Mitglied
wenn ich das jetzt so vergleiche kriege ich eine NPE. Liegt wohl daran dass shops nochnicht erzeugt wurde?
Java:
package edu.hm.cs.swe2.shoppingmall;

import static org.junit.Assert.assertEquals;

import org.junit.jupiter.api.Test;

public class ShoppingMallTest {

    @Test
    public void testShoppingMall() {
        int shopCountTest = 0;
        // Testwert bestimmen
        ShoppingMall testShoppingMall = new ShoppingMall(shopCountTest);
        // erzeugt ein Objekt ShoppingMall mit Testwert
        int expectedResult = 10;
        // zu erwartende Länge des Array der durch Shoppingmal erzeugt wird mit Testwert
        // 0
        int actualResult = testShoppingMall.size();

        assertEquals(expectedResult, actualResult);
    }

}
 
K

kneitzel

Gast
Ja, das ist Sinn der Unit-Tests. Du hast einen Fehler gefunden und musst den nun beheben.

Schauen wir uns einmal diesen Code an:
Code:
    public ShoppingMall(int shopCount) {
        if (shopCount < 1 || shopCount > 500) {
            shopCount = 10;
        } else {
            this.shops = new Shop[shopCount];
        }
    }


Überlege einmal genau, was passiert, wenn shopCount < 1 oder > 500 ist. Was ist dann shops?
 

nikva

Bekanntes Mitglied
ok ich sehe es. wenn eine der beiden Bedingungen erfüllt ist, dann wird shops nicht erzeugt, weil der else zweigt nicht erreicht wird. Ich muss also auch im if zweig mit this.shops = new Shop[10]; direkt das shops array erzeugen
 

nikva

Bekanntes Mitglied
Ich habe jetzt alle Klassen fertig und will jetzt die restlichen Tests erstellen. In der Aufgabenstellung heißt es, dass alle "relevanten Methoden" getestet werden sollen. Void Methoden wurden ausgeschlossen, aber getter,Setter und Konstruktoren ohne Bedingungen zu testen ist auch nicht besonders sinnvoll und fällt wohl auch nicht unter "relevante Methoden", oder?
 

LimDul

Top Contributor
Ich habe jetzt alle Klassen fertig und will jetzt die restlichen Tests erstellen. In der Aufgabenstellung heißt es, dass alle "relevanten Methoden" getestet werden sollen. Void Methoden wurden ausgeschlossen, aber getter,Setter und Konstruktoren ohne Bedingungen zu testen ist auch nicht besonders sinnvoll und fällt wohl auch nicht unter "relevante Methoden", oder?
Schwierig zu beantworten. Ich gebe dir jetzt mal an, wie ich es aus der Praxis sehen würde - allerdings sind Uni-Aufgaben nicht immer gleich zur Praxis:

Relevant ist alles, wo selbstgeschriebener Code drin ist
Das heißt, alles was nicht generiert ist. Abstriche macht man in der Regel:
* Bei simplen gettern/settern (die also nur aus return this.variable; bzw. this.variable = variable; bestehen). Die sind ja auch oft quasi mit IDE Board-Mitteln generiert.
* Konstruktoren, da die zum einem meist nur aus Zuweisungen bestehen, zum anderen in der Regel von den restlichen Tests mit abgedeckt werden.
* Private Methoden, da diese nicht zur öffentlichen Schnittstelle gehören - und mit den Tests will ich ja sicherstellen, dass die öffentliche Schnittstelle korrekt arbeiten (Die werden in der Regel implizit mitgetestet)

Aber auch void-Methodne sind normalerweise relevant! Den auch diese Methoden machen etwas sinnvolles was man testen sollte. Wenn sie nichts tun, könnte man sie auch löschen.

Ziel sollte sein, eine möglichst Hohe Codeabdeckung (in Eclipse z.B. mittels EclEmma als Plugin messbar) zu erreichen.
 

White_Fox

Top Contributor
Irgendwer sagte mir hier mal, daß ein Test eine Demonstration sein solle, wie mit einer Klasse zu arbeiten sei. Ich glaube, @mrBrown war das mal gewesen. Jedenfalls ist diese Betrachtung gar nicht so doof.

Simple setter- und Gettermethoden teste ich eigentlich auch immer mit, da es doch hin und wieder mal vorkommt daß die Methode geändert wird wenn man an der internen Implementierung herumpfuscht.

Allgemein sind Tests auch immer nützlich, um herauszufinden, ob eine Klasse nach außen hin noch genau dasselbe macht nachdem man z.B. intern viel geändert hat.

Ich z.B. sitze gerade an dem Problem, daß mir der Code in einer Klasse völlig ausufert. Der Test dieser Klasse ist recht umfangreich, da viele verschiedene Testszenarien, jedoch ist die Klasse auch >1.200 Codezeilen lang.
Da es mittlerweile schwierig wird, da noch die Übersicht zu behalten, andererseits neue Erweiterungen (mindestens eine steht noch an) immer hakeliger werden, baue ich die interne Struktur gerade völlig um.
Die Klasse ist intern sehr prozedural aufgebaut, jetzt lagere ich viel Code an kleinere, neue Klassen aus. Ursprünglich gab es für die interne Funktionsweise nur zwei Klassen, jetzt werden es sieben (und eine achte steht an).

Und mit dem Unittest kann ich jetzt testen, ob alles hinterher genauso funktioniert wie vorher. Nach solchen Umbauten kann ein Test nicht umfangreich genug sein. Daher: Teste ruhig mehr als weniger.
 
Zuletzt bearbeitet:

nikva

Bekanntes Mitglied
Klingt vernünftig.
Beim Testen von ToyStore(Aufgabe 6) habe ich jetzt das Problem, dass sich die Miete durch die geöffneten Stunden und die Stundenmiete berechnet.
Nun wird aber nicht bei jedem Toystore die Öffnungszeit angegeben,weswegen ich 2 Konstruktoren habe: einen mit und einen ohne Öffnungszeiten.
in Aufgabe 13 muss man jetzt einen Toystore ohne Öffnungszeiten erstellen:
e) Erzeugen Sie den Spielzeugladen „Cool Toys“ mit 150qm und 12,50 Miete. Der Laden öffnet um 9 Uhr und schließt um 17 Uhr.
f) Erzeugen Sie den Spielzeugladen „Cheap Toys“ mit 150qm und 5,50 Miete.
Beim Testen kriege ich jetzt aber logischerweise einen Fehler wenn ich den Testcase der ohne Öffnungszeiten erstellt wurde teste. Ist das ein Problem oder wurde das einfach in der Aufgabenstellung vergessen?

Java:
package edu.hm.cs.swe2.shoppingmall;

import static org.junit.Assert.assertEquals;

import java.time.LocalTime;

import org.junit.jupiter.api.Test;

class ToyStoreTest {
    @Test
    public void testgetRent() {
        ToyStore testToyStore = new ToyStore("Testshop", 300, 12.50, LocalTime.of(9, 0), LocalTime.of(15, 0));
        double expectedResult = 75.0;
        double actualResult = testToyStore.getRent();
        assertEquals(expectedResult, actualResult, 0);

        ToyStore testToyStore2 = new ToyStore("Testshop2", 300, 12.50);
        double expectedResult2 = 75.0;
        double actualResult2 = testToyStore2.getRent();
        assertEquals(expectedResult2, actualResult2, 0);
    }
}

Java:
package edu.hm.cs.swe2.shoppingmall;

import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class ToyStore extends Shop {

    public ToyStore(String name, int area, double rent, LocalTime openingTime, LocalTime closingTime) {
        super(name, area, rent);
        this.openingTime = openingTime;
        this.closingTime = closingTime;
    }

    public ToyStore(String name, int area, double rent) {
        super(name, area, rent);
    }

    @Override
    public double getRent() {
        return rent * openingTime.until(closingTime, ChronoUnit.HOURS);
    }
}
 

nikva

Bekanntes Mitglied
Ich will in meinem Test ja manchmal auf die Attribute zugreifen und das geht nicht wenn die Sichtbarkeit auf private gesetzt ist.
 

thecain

Top Contributor
Davon ging ich aus... Aber private Attribute müssen ja irgendwo verwendet werden, das public ist. Teste doch das, dann sollte die private Variable automatisch mitgetestet sein.
 

nikva

Bekanntes Mitglied
Java:
    Supermarket testSupermarket = new Supermarket("Testshop", 200, 50, 40);
   @Test
    void testAddPerson() {
        int expectedResult = 39;
        testSupermarket.addPerson();
        assertEquals(expectedResult, testSupermarket.availableCarts);
    }

Java:
    public void addPerson() {
        availableCarts--;
        soundAlarm();
    }
aber wie lässt sich das hier anders lösen als mit einem getter? Auch wenn die Methode public ist muss ich doch auf das Attribut zugreifen und das ist nunmal private. Oder muss man dafür ein ganz neues Attribut aufrufen?
 

LimDul

Top Contributor
Java:
    Supermarket testSupermarket = new Supermarket("Testshop", 200, 50, 40);
   @Test
    void testAddPerson() {
        int expectedResult = 39;
        testSupermarket.addPerson();
        assertEquals(expectedResult, testSupermarket.availableCarts);
    }

Java:
    public void addPerson() {
        availableCarts--;
        soundAlarm();
    }
aber wie lässt sich das hier anders lösen als mit einem getter? Auch wenn die Methode public ist muss ich doch auf das Attribut zugreifen und das ist nunmal private. Oder muss man dafür ein ganz neues Attribut aufrufen?
Was genau willst du - losgelöst vom Code testen?

a) Das nun nur 19 Carts zur Verfügung stehen?
- Ist das eine öffentliche Information deines Supermarktes, gehört es also zur öffentlichen API das ein User des Supermarkt-Objekts drauf zugreifen kann? Dann sollte es auch einen getter geben, mit dem man das testen kann
- Es ist keine öffentliche Information - dann ist es für den Test nicht relevant welchen Wert es hat. Dann ist der Test nicht sinnvoll, weil er den internen Zustand des Objekts testest
b) Du willst testen, das nur dann eine Person in den Supermarkt kann, wenn ein Cart zur Vefügung steht? Test 1: Dann initialisiere deinen Supermarkt z.B. mit 2 Carts, rufe addPerson 2x auf => Muss gehen. Test 2: Wieder mit 2 Carts, aber addPerson 3x aufrufen => Verhalten bei nicht mehr verfügbaren Carts erwarten
 

nikva

Bekanntes Mitglied
Aber das wird ja in diesem Fall, auch wenn es nicht logisch ist, immer gehen und availablecarts wird negativ. Eine Bedingung ist aber denke ich nicht vorgesehen da addPerson laut Aufgabenstellung mit 3 Zeilen zu implementieren ist. Mit Bedingung komme ich aber auf 5
Java:
    public void addPerson() {
        if (availableCarts > 0) {
            availableCarts--;
            soundAlarm();
        } else {
            System.out.println("no carts available");
        }
    }
Vielleicht dann doch einfach mit Getter, oder wäre das gegen die Konventionen wenn ich den nur für den Test nutze?
 

White_Fox

Top Contributor
Du kannst mittels Reflection in den privaten Eingeweiden eines Objekts herumpopeln, aber normalerweise ist das tabu.

Bedenke auch: Wenn du die Implementierung änderst, dann mußt du den Test mitändern. Das ist aufwändig, und mieser Stil obendrein. Genauso stattet man eine Klasse auch nicht mit Methoden aus die man eigentich nicht braucht, und die nur im Unittest vorkommen.

Wenn du eine setter-Methode hast, und keine direkt passende getter-Methode - dann würde ich einen Test schreiben der einfach die setter-Methode aufruft - und das wars. Auch wenn kein Ergebnis direkt geprüfgt wird, so zeigt der Test immer noch daß die Aktion keine Nullpointerexception wirft oder ähnlicher Unsinn geschieht.
Oder wie jemand anders schrieb: Du verzichtest auf den Test.
 

White_Fox

Top Contributor
Naja...hänge dich lieber weniger damit auf ob das jetzt eine void-Methode ist oder nicht.

Das große Problem bei Entwicklungsaufgaben ist: es gibt keine vorgefertigte Lösung. Was sinnvoll ist und was nicht, das mußt du selber entscheiden (das kann nicht jeder, selbst ein erfolgreicher Abschluß ist nicht mehr unbedingt ein Beleg das man dieses autonome Denken hat) und ich denke mal, darauf zielt die Aufgabe auch etwas ab.

Auch wenn es vielleicht etwas dämlich klingt: An deiner Stelle würde ich mich mal eine halbe Stunde einfach nur hinsetzen und einfach nur darüber nachdenken, was der Sinn eines Unittest ist. Was will man damit erreichen, und was nicht? Überleg dir Probleme und Lösungen dazu.
Das bereitet einen vielleicht weniger direkt auf eine Prüfung vor, macht einen aber zu einem besseren Entwickler als das stumpfe Lösen von Übungsaufgaben.
 

nikva

Bekanntes Mitglied
Oder ich rufe einfach 2 mal die Methode auf
Java:
class SupermarketTest {

    Supermarket testSupermarket = new Supermarket("Testshop", 200, 50, 1);

    @Test
    void testGetPersonCount() {

        testSupermarket.addPerson();
        testSupermarket.addPerson();
    }
so beweise ich ja im Prinzip auch, dass beide Zweige funktionieren und ich muss auch nicht auf das Attribut zugreifen obwohl es trotzdem in der Methode verarbeitet wird.
 
K

kneitzel

Gast
Du musst dennoch das Ergebnis überprüfen. Ein Test ohne Assert Aufrufe testet doch (fast) nichts. So lange die Methode keine Exception wirft, ist der Test ja erfolgreich!
 

nikva

Bekanntes Mitglied
Java:
    @Test
    void testGetPersonCount() {
        Supermarket testSupermarket = new Supermarket("Testshop", 1, 50, 1);
        testSupermarket.addPerson();
        int expectedResult = 1;
        assertEquals(expectedResult, testSupermarket.getPersonCount());
        testSupermarket.addPerson();
        int expectedResult2 = 1;
        assertEquals(expectedResult2, testSupermarket.getPersonCount());
    }
Ich teste es einfach über die getPersonCount() Methode.
 
K

kneitzel

Gast
Also nach dem Code, den du bisher gezeigt hast, ist das nicht ein ausreichender Test.

Ich nehme einmal diese (frühere) Version:
Code:
    public void addPerson() {
        availableCarts--;
        soundAlarm();
    }

Da sieht man, dass Du etwas mit availableCarts machst. Also musst Du das testen. Das kann man prinzipiell über einen Getter machen.

Aber das aus soundAlarm() wird nicht geprüft. Was macht dies? Du musst sicher stellen, dass diese Funktionalität auch im Zusammenhang mit der addPerson getestet wird.
Derzeit wäre es wohl möglich, in Deinem Code diesen Aufruf zu löschen und der Test wäre immer noch erfolgreich. Entweder braucht man es nicht, dann lösche es oder man braucht es, dann teste, ob es gemacht wurde.

Ein weiterer Punkt, der nicht an dem Code festgemacht werden kann: Etwas später kommt ein Beispiel, bei dem Du prüfst, ob noch ein Einkaufswagen da ist. Wenn Du so einen Fall jetzt im Code hast, dann hast Du da natürlich auch zu testen, dass dies statt findet.

Jetzt ist nur die Frage: Wie testet man sowas? Wie kann ich schauen, ob ein System.out.println erfolgt ist oder nicht?
Eine Möglichkeit ist, dass man das, was diese Aktion macht, ersetzt. Bei System.out geht das z.B. über System.setOut. So ich diese Möglichkeit habe, dann nutze ich diese natürlich. Hier hat das Java Framework schon die notwendigen Mittel bereit gestellt.
Aber das ist ja nicht immer der Fall. Ich sehe da mehrere Möglichkeiten, die alle in etwa auf das Gleiche hinaus laufen. Ich trenne die Funktionalität etwas auf.
Um das zu lösen sehe ich eine Möglichkeit, die ich kurz vorstellen möchte: Das soundAlarm() fliegt da raus. Statt dessen wird diese Funktionalität verlagert und es gibt eine Schnittstelle, mir der man Funktionalität setzen kann. Wie dies im Detail implementiert ist, kann unterschiedlich sein:
- Events - Dann gibt es da ein Event, zu dem man sich melden kann. Dein Test registriert sich dann um zu prüfen, ob er aufgerufen wird oder eben nicht. (z.B. durch erhöhen eines Zählers im Test oder so ...)
- Strategy Pattern kommt einem da ebenfalls in den Sinn.
- Abhängigkeiten - es gibt eine Abhängigkeit und diese kann dann bei einem Test durch ein neues Element (Mocking) ersetzt werden. (Ist teilweise vom Prinzip eigentlich ähnlich wie das Startegy Pattern .... Hier hat man halt auch meist ein DI Framwork im Einsatz, aber das ist natürlich optional ...
 

nikva

Bekanntes Mitglied
Da sieht man, dass Du etwas mit availableCarts machst
Code:
    public int getPersonCount() {
        return maxCarts - availableCarts;
    }
available Carts ist ja auch in getPersonCount() und einen Getter wollte ich ja nicht extra für den Test implementieren, aber wenn es nicht anders geht mache ich das wohl.
Um das zu lösen sehe ich eine Möglichkeit, die ich kurz vorstellen möchte: Das soundAlarm() fliegt da raus. Statt dessen wird diese Funktionalität verlagert und es gibt eine Schnittstelle, mir der man Funktionalität setzen kann. Wie dies im Detail implementiert ist, kann unterschiedlich sein:
soundalarm ist bereits Teil einer Schnittstelle
Java:
package edu.hm.cs.swe2.shoppingmall;

public interface SecurityCountable {

    void addPerson();

    void removePerson();

    int getPersonCount();

    static void soundAlarm() {
    }
}
Aber, da heute Abgabe ist, mach ich mich erstmal daran alle Klassen mit rudimentären Tests zu belegen und wenn noch Zeit bleibt arbeite ich die Print Meldungen in den Test ein, die ohnehin schon ausdrücklich nicht abgedeckt werden müssen.
 
K

kneitzel

Gast
Also wenn die Ausgabe nicht abgedeckt werden muss, dann ist es ok. Dann fordert es die Aufgabe nicht.

Was das soundalarm angeht, da sehe ich aber immer noch Bedarf. Das soundalarm wird nicht getestet, d.h. wenn jemand etwas kaputt macht (ich lösche den Aufruf einfach raus), dann läuft Dein Test immer noch erfolgreich durch. Aber eine static method in einem Interface - das wird blöd zu testen. Da sehe ich keinen ganz einfachen Weg mehr. JMockIt kann wohl auch mit statischen Methoden umgehen wie z.B. Baeldung hier zeigt: https://www.baeldung.com/jmockit-static-method

Aber das ist kein wirklich schönes Design - ich habe auf sowas immer gut verzichtet. Static Methoden sind schon evil ... in Interfaces ist das dann evil hoch zwei oder so :) Aber ich möchte natürlich nicht ausschließen, dass es auch Anwendungsfälle gibt, wo man dies braucht.... (Singleton Pattern gibt es ja z.B. auch, auch wenn das durch DI im Backend eigentlich verschwunden ist ....)

Da wäre es evtl. interessant, wenn da auch mal Andere was zu sagen ... @mrBrown? @mihe7? Ist zwar für Deine Aufgabe ggf. irrelevant (weil ihr das so nicht behandelt habt), aber mich würde das schon interessieren ...
 
K

kneitzel

Gast
Wenn es in der Aufgabe nicht ausgeschlossen ist, dann solltest Du in Deinem Test aber auch abprüfen, dass dieser Aufruf erfolgte. Sprich: Wenn Du den Aufruf auskommentierst, dann muss der Test einen Fehler melden... Ohne die genaue Implementation zu kennen kann ich dir da aber auch keine Vorschläge machen, wie das am Besten gehen würde ...
 

nikva

Bekanntes Mitglied
Java:
package edu.hm.cs.swe2.shoppingmall;

public interface SecurityCountable {

    void addPerson();

    void removePerson();

    int getPersonCount();

    void soundAlarm();
}
Java:
package edu.hm.cs.swe2.shoppingmall;

public class Supermarket extends Shop implements SecurityCountable {

    private int maxCarts;
    private int availableCarts;

    public Supermarket(String name, int area, double rent, int maxCarts) {
        super(name, area, rent);
        this.maxCarts = maxCarts;
        this.availableCarts = maxCarts;
    }

    public void addPerson() {
        if (availableCarts > 0) {
            availableCarts--;
            soundAlarm();
        } else {
            System.out.println("no carts available");
        }
    }

    public void soundAlarm() {
        if ((getArea() / getPersonCount()) < 20) {
            System.out.println("too many customers in the supermarket!");
        }

    }

    public void removePerson() {
        if (availableCarts < maxCarts) {
            availableCarts++;
        } else {
            System.out.println("there is no Person in the supermarket");
        }
    }

    public int getPersonCount() {
        return maxCarts - availableCarts;
    }
}
Java:
package edu.hm.cs.swe2.shoppingmall;

import static org.junit.Assert.assertEquals;

import org.junit.jupiter.api.Test;

class SupermarketTest {

    @Test
    void testGetPersonCount() {
        Supermarket testSupermarket = new Supermarket("Testshop", 1, 50, 1);
        testSupermarket.addPerson();
        assertEquals(1, testSupermarket.getPersonCount());
        testSupermarket.addPerson();
        assertEquals(1, testSupermarket.getPersonCount());
    }

    @Test
    void testRemovePerson() {
        Supermarket testSupermarket2 = new Supermarket("Testshop", 200, 50, 40);
        testSupermarket2.addPerson();
        assertEquals(1, testSupermarket2.getPersonCount());
        testSupermarket2.removePerson();
        assertEquals(0, testSupermarket2.getPersonCount());
        testSupermarket2.removePerson();
        assertEquals(0, testSupermarket2.getPersonCount());
    }

    @Test
    void testAddPerson() {
        Supermarket testSupermarket3 = new Supermarket("Testshop", 200, 50, 40);
        testSupermarket3.addPerson();
        assertEquals(1, testSupermarket3.getPersonCount());

    }
}
So sieht das komplett aus und nach dem Schema hab ich das auch in den anderen Klassen gemacht, auch wenn es, wie ihr zurecht anmerkt, kein kompletter Test ist.
Die Anforderung stehen in Aufgabe 5 in der Aufgabenstellung im Eingangspost und ich glaub die überprüfung nach availableCarts ist ohnehin nicht vorgesehen, wenn man sich die angegebenen Zeilen code ansieht.
 

nikva

Bekanntes Mitglied
in einer Aufgabe heißt es:
c) Überlegen Sie warum diese Klasse schlecht testbar ist (mittels Unit Tests) und was man am Programm ändern könnte, um dies zu verbessern. Dokumentieren Sie dies im PDF mit dem Klassendiagramm. Die Verbesserung ist aber nicht zu implementieren.
es handelt sich um folgende Klasse:
Code:
package edu.hm.cs.swe2.shoppingmall;

public class Playground implements SecurityCountable {
    private int numberOfKids;

    @Override
    public void addPerson() {
        numberOfKids++;
        soundAlarm();

    }

    @Override
    public void removePerson() {
        numberOfKids--;

    }

    @Override
    public int getPersonCount() {
        return numberOfKids;
    }

    @Override
    public void soundAlarm() {
        if (numberOfKids > 50) {
            System.out.println("too many Kids on the playground, acces denied!");
            numberOfKids--;
        }
    }

}
Ich nehme mal an es liegt daran, dass ein Playground nur über den KidsFashionShop erstellt und die Methoden auch nur darüber aufgerufen werden. Also ist es auch wenn man die Methoden testen könnte nicht sonderlich Sinnvoll dies zu tun?

Java:
package edu.hm.cs.swe2.shoppingmall;

public class KidsFashionShop extends FashionShop {
    private Playground playground;

    public KidsFashionShop(String name, int area, double rent) {
        super(name, area, rent);
        this.playground = new Playground();
    }

    public void addKid() {
        playground.addPerson();
    }

    public void pickUpKid() {
        playground.removePerson();
    }

    public int getNumberOfKids() {
        return playground.getPersonCount();
    }
}
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Länge eines Arrays als Variable speichern möglich? Java Basics - Anfänger-Themen 14
A Arrays kombinieren (länge eines Arrays kann 0 sein) Java Basics - Anfänger-Themen 6
O Länge eines Arrays Java Basics - Anfänger-Themen 6
E Länge eines spez. Arrays Java Basics - Anfänger-Themen 10
D prüfen ob länge eines Arrays == 0 Java Basics - Anfänger-Themen 4
B Maximale Länge eines integer Arrays ? Java Basics - Anfänger-Themen 31
B Länge eines Char-Arrays bestimmen Java Basics - Anfänger-Themen 7
G länge eines arrays bestimmen Java Basics - Anfänger-Themen 4
D Länge eines Objekt-Arrays Java Basics - Anfänger-Themen 7
F Maximale Länge eines Strings Java Basics - Anfänger-Themen 5
L Länge der dritten Dimension eines dreidimensionalen Arraya Java Basics - Anfänger-Themen 1
Z Erste Schritte Einlesen der Länge eines Feldes Java Basics - Anfänger-Themen 25
S Länge eines Elements im String Array Java Basics - Anfänger-Themen 5
S Länge eines zweidimensionalen Feldes Java Basics - Anfänger-Themen 3
E Länge eines Feldes ausgeben Java Basics - Anfänger-Themen 13
V Warten bis die Länge eines Strings nicht mehr 0 ist Java Basics - Anfänger-Themen 13
J Länge eines long wertes Java Basics - Anfänger-Themen 13
G Länge eines Integers ermitteln? Java Basics - Anfänger-Themen 38
G Länge eines Array trimmen oder dynamisch verändern. Java Basics - Anfänger-Themen 3
B Länge eines JTextFields Java Basics - Anfänger-Themen 3
G Länge eines zweidimensionalen array Java Basics - Anfänger-Themen 2
R länge eines array? Java Basics - Anfänger-Themen 6
C Länge/Anzahl der Stellen eines Integers Java Basics - Anfänger-Themen 8
H Liste nach String-Länge sortieren Java Basics - Anfänger-Themen 1
D Länge einer Liste aufrufen. Java Basics - Anfänger-Themen 19
S Die durchschnittliche Länge der Strings Java Basics - Anfänger-Themen 11
Hzrfa Länge der längsten Kette java Java Basics - Anfänger-Themen 56
BeginnerJava String mit vorgegebener Länge und Buchstaben erzeugen/ mit Leerstellen Java Basics - Anfänger-Themen 8
JavaBeginner22 Wort mit der größten Länge ausgeben Java Basics - Anfänger-Themen 4
I Array Länge in Klasse festlegen Java Basics - Anfänger-Themen 1
Csircc Neuer Array mit geringerer Länge und selben werten. Java Basics - Anfänger-Themen 2
P Länge des längsten möglichst klein Java Basics - Anfänger-Themen 2
districon 2D Array - Länge zuweisen Java Basics - Anfänger-Themen 1
t2im Java Array-Länge ändern? Java Basics - Anfänger-Themen 22
W Best Practice Tabulatoren verschiedener Länge ersetzen Java Basics - Anfänger-Themen 8
H Klassen Die Länge einer Text-Node bestimmen Java Basics - Anfänger-Themen 2
J Objekt-Array dynamischer Länge aus Benutzereingaben erstellen Java Basics - Anfänger-Themen 6
G Variablen Array Länge über den Konstruktor definieren Java Basics - Anfänger-Themen 4
M Strings mit gerader und ungerader Länge ausgeben Java Basics - Anfänger-Themen 10
L Zwei sortierte Subarrays mit gleicher Länge zusammenfügen Java Basics - Anfänger-Themen 2
S Java Array Länge aus anderer Klasse lesen Java Basics - Anfänger-Themen 1
M Die länge von char Java Basics - Anfänger-Themen 6
A Best Practice Undefinierte länge bei arrays Java Basics - Anfänger-Themen 4
E Array-list mit einer bestimmten Länge Java Basics - Anfänger-Themen 17
T Länge einer Textdatei Java Basics - Anfänger-Themen 11
C Array - Länge dynamisch übergeben Java Basics - Anfänger-Themen 7
N Array mit unbestimmter länge Java Basics - Anfänger-Themen 12
T String länge messen in mm Java Basics - Anfänger-Themen 1
M Generierter Tannenbaum - String Länge Java Basics - Anfänger-Themen 1
T String/int länge Java Basics - Anfänger-Themen 2
I Länge von mehrdimensionalen Array Java Basics - Anfänger-Themen 5
A Länge Substring Java Basics - Anfänger-Themen 1
D Zweidimensionales Array (Länge) Java Basics - Anfänger-Themen 2
S Listnode Länge Java Basics - Anfänger-Themen 2
shiroX Input/Output Array erstellen / Länge Java Basics - Anfänger-Themen 3
G Erste Schritte berechne länge von einträgen Java Basics - Anfänger-Themen 5
S Länge einer Zahl Java Basics - Anfänger-Themen 18
C Datentypen Array-Einträge überhalb der Array-Länge - welcher Wert? Java Basics - Anfänger-Themen 5
M Strings mit variabler Länge auffüllen Java Basics - Anfänger-Themen 6
J Alle Wörter der Länge n mit 0 und 1 Java Basics - Anfänger-Themen 17
C Datentypen Array mit dynamischer Länge? Java Basics - Anfänger-Themen 14
M Länge der Strecke zwischen zwei Punkten Java Basics - Anfänger-Themen 10
P länge von array abfragen? Java Basics - Anfänger-Themen 2
D Erste Schritte Warum wird bei einem Array die Länge über Length ausgegeben? Java Basics - Anfänger-Themen 6
M Länge String Java Basics - Anfänger-Themen 3
A Länge einer Hexadezimalzahl in Bits Java Basics - Anfänger-Themen 40
P String- Länge Java Basics - Anfänger-Themen 3
A Klassen Eigene Datenklasse - Strings mit fixer Länge Java Basics - Anfänger-Themen 2
Gossi Datentypen Länge von Zahlentypen Java Basics - Anfänger-Themen 3
G Array mit zufälliger Länge Java Basics - Anfänger-Themen 4
S Datentypen String mit fester Länge (Rückgabewert einer Methode) Java Basics - Anfänger-Themen 2
D Array anlegen ohne bekannte Länge? Java Basics - Anfänger-Themen 6
S ArrayList länge lässt sich nicht voreinstellen Java Basics - Anfänger-Themen 10
F String begrenzte Länge??? Java Basics - Anfänger-Themen 16
N List länge Java Basics - Anfänger-Themen 6
DStrohma Binärwörter der Länge n ausgeben Java Basics - Anfänger-Themen 3
A array und seine länge Java Basics - Anfänger-Themen 5
G länge von string, string aus integer/char Java Basics - Anfänger-Themen 6
G Länge einer Enumeration feststellen Java Basics - Anfänger-Themen 15
T Länge von Strings im Array vergleichen Java Basics - Anfänger-Themen 2
N Array bei unbekannter Länge Java Basics - Anfänger-Themen 4
M unerklärbarer Fehler bei Array-Länge Java Basics - Anfänger-Themen 4
R Frage zur Länge von Textfeld und String Java Basics - Anfänger-Themen 4
G Warum hat char die Länge 2? Java Basics - Anfänger-Themen 9
B JTable - Einstellen der Größe bzw. der Länge Java Basics - Anfänger-Themen 1
J Char-Array mit variabler Länge zurückliefern. Java Basics - Anfänger-Themen 11
G Keine feste Länge bei Objekten, warum nur Zeiger? Java Basics - Anfänger-Themen 8
F ArrayList Länge ermitteln und ausgeben Java Basics - Anfänger-Themen 13
M länge von wörtern betimmen Java Basics - Anfänger-Themen 20
NightmareVirus Länge einer Integerzahl bestimmt Java Basics - Anfänger-Themen 6
B 2D Punkte erstellen und ihre Länge berechnen/Problem this. Java Basics - Anfänger-Themen 3
L String konstante Länge? Java Basics - Anfänger-Themen 4
R maximale Länge des INHALTS im JTextField Java Basics - Anfänger-Themen 2
R String[][] mit variabler länge Java Basics - Anfänger-Themen 4
G länge einer audiodatei herausfinden Java Basics - Anfänger-Themen 3
M Maximale String länge finden? Java Basics - Anfänger-Themen 8
G Array-Länge bei Erzeugung noch unbekannt - wie erzeugen? Java Basics - Anfänger-Themen 12
J Arrays mit unbekannter Länge Java Basics - Anfänger-Themen 2
B String aus Datei lesen + Länge berechnen Java Basics - Anfänger-Themen 2
N Ermitteln der Spaltenbreite => DATE-Spalte hat Länge 8 ?! Java Basics - Anfänger-Themen 10

Ähnliche Java Themen

Neue Themen


Oben