Проект Maven — коллекции HashMap и HashSet с тестированием JUnit

Опубликовано: 19 Февраля, 2023

Во многих программах мы будем работать с HashMap и HashSet, и всегда существует путаница, когда использовать HashMap и когда использовать HashSet. В качестве примера проекта взят вариант использования, содержащий класс «GeekAuthor», и он имеет разные атрибуты, а именно

  • имя автора
  • идентификатор автора
  • круг интересов
  • опубликованные статьи

Давайте попробуем добавить данные «GeekAuthor» как в HashMap, так и в HashSet по отдельности и проверим поведение по одному. Наряду с JUNIT мы также можем эффективно тестировать.

Пример проекта Maven

Структура проекта:

Проект подготовлен как тип maven и, следовательно, все зависимости, необходимые для проекта, присутствуют в

пом.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
  
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gfg.CollectionServicesInJava</groupId>
    <artifactId>CollectionServicesInJava</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
  
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>5.3.1</junit.version>
        <pitest.version>1.4.3</pitest.version>
    </properties>
  
    <dependencies>
  
        <!-- junit 5, unit test -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
  
    </dependencies>
    <build>
        <finalName>maven-mutation-testing</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M1</version>
            </plugin>
  
            <plugin>
                <groupId>org.pitest</groupId>
                <artifactId>pitest-maven</artifactId>
                <version>${pitest.version}</version>
  
                <executions>
                    <execution>
                        <id>pit-report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>mutationCoverage</goal>
                        </goals>
                    </execution>
                </executions>
                  
                <!-- Need this to support JUnit 5 -->
                <dependencies>
                    <dependency>
                        <groupId>org.pitest</groupId>
                        <artifactId>pitest-junit5-plugin</artifactId>
                        <version>0.8</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <targetClasses>
                        <param>com.gfg.CollectionServicesInJava.*CollectionServicesInJava*</param>
                    </targetClasses>
                    <targetTests>
                        <param>com.gfg.CollectionServicesInJava.*</param>
                    </targetTests>
                </configuration>
            </plugin>
  
        </plugins>
    </build>
  
</project>

Поскольку мы собираемся добавить GeekAuthors, нам нужен класс модели для него.

GeekAuthor.java

Java




package com.gfg.CollectionServicesInJava;
  
public class GeekAuthor {
    public GeekAuthor(String authorName, int authorId, String areaOfInterest, int publishedArticles) {
        super();
        this.authorName = authorName;
        this.authorId = authorId;
        this.areaOfInterest = areaOfInterest;
        this.publishedArticles = publishedArticles;
    }
  
    public GeekAuthor() {
        // via setter methods, rest fields are done
    }
  
    String authorName;
    int authorId;
    String areaOfInterest;
    int publishedArticles;
  
    public String getAuthorName() {
        return authorName;
    }
  
    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }
  
    public int getAuthorId() {
        return authorId;
    }
  
    public void setAuthorId(int authorId) {
        this.authorId = authorId;
    }
  
    public String getAreaOfInterest() {
        return areaOfInterest;
    }
  
    public void setAreaOfInterest(String areaOfInterest) {
        this.areaOfInterest = areaOfInterest;
    }
  
    public int getPublishedArticles() {
        return publishedArticles;
    }
  
    public void setPublishedArticles(int publishedArticles) {
        this.publishedArticles = publishedArticles;
    }
  
    // We need to override 2 methods namely 
    // equals and hashcode whenever we no need
    // to store two author objects     
    // if their names are same
    @Override
    public boolean equals(Object o) {
        if (o instanceof GeekAuthor) {
            GeekAuthor other = (GeekAuthor) o;
            return authorName.equals(other.getAuthorName());
        }
  
        return false;
    }
  
    @Override
    public int hashCode() {
        return authorName.hashCode();
    }
  
}

Здесь нам нужно обратить внимание на два конкретных метода, а именно «equals» и «hashCode». Они должны быть переопределены в соответствии с нашими требованиями. Эти два метода по существу необходимы для проверки того, являются ли объекты дубликатами или нет. Они снова приведены здесь для справки.

// We need to override 2 methods namely equals
// and hashcode whenever we no need
// to store two author objects     
// if their names are same
@Override
public boolean equals(Object o) {
        if (o instanceof GeekAuthor) {
            GeekAuthor other = (GeekAuthor) o;
            return authorName.equals(other.getAuthorName());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return authorName.hashCode();
    }

Этот набор кода очень важен, и только функциональность HashSet запрещает дублирование. Здесь нам нужно знать, что HashMap допускает дублирование ключей, но что произойдет, так это то, что новые добавленные данные будут перезаписаны вместо старых данных. Например

authorMap.put("Rachel",new GeekAuthor("Rachel", 1, "Java", 200));
authorMap.put("Monica",new GeekAuthor("Monica", 1, "Python", 100)); 
authorMap.put("Rachel",new GeekAuthor("Phoebe", 1, "Java", 100));
In line 1 and 3, "Rachel" is the key. Hence finally in the HashMap we can able to see only 2 entries only
and when we try to retrieve the data for "Rachel" key, we will get 
authorName as Phoebe, authorId as 1 etc.,
i.e. 1st data is overwritten

Теперь, что касается HashSet, если мы попытаемся добавить повторяющиеся данные, они вообще не будут учитываться из-за существующих двух методов, а именно «equals» и «hashCode».

GeekAuthor rachel = new GeekAuthor("Rachel", 1, "Java", 200);
GeekAuthor monica = new GeekAuthor("Monica", 1, "Python", 100);
GeekAuthor phoebe = new GeekAuthor("Rachel", 1, "Java", 200);
authorSet.add(rachel);
authorSet.add(monica); 
authorSet.add(phoebe);
Here though "phoebe" named author object is created and since it is a duplicate value ("rachel" named author
objectis already added with the same data, finally only 2 author data is there.

Давайте посмотрим полный набор кодов через

HashMapCollectionServicesInJava.java

Java




import java.util.HashMap;
  
public class HashMapCollectionServicesInJava {
    // In order to represent HashMap does not allow 
    // duplicates in a HashMap for the same key "Rachel", 
    // two separate author data is added
    // Though adding is allowed, instead of keeping
    // 3 different entries, only 2 will be the size and for
    // "Rachel" key, last data is updated
    public int addAuthors(HashMap authorMap) 
    {
        authorMap.put("Rachel",new GeekAuthor("Rachel", 1, "Java", 200));
        authorMap.put("Monica",new GeekAuthor("Monica", 1, "Python", 100)); 
        authorMap.put("Rachel",new GeekAuthor("Phoebe", 1, "Java", 100)); 
        return authorMap.size();
    }
    public int getAuthors(HashMap authors) {
        return authors.size();
    }
    public String getAuthorName(HashMap authorMap,String authorNameKey) {
        GeekAuthor geekAuthor = new GeekAuthor();
        if (authorMap.containsKey(authorNameKey)) {
            // Mapping the retrieved value
            geekAuthor = (GeekAuthor) authorMap.get(authorNameKey);            
        }
        return geekAuthor.getAuthorName();
    }
  
}

HashSetCollectionServicesInJava.java

Java




import java.util.HashSet;
import java.util.Set;
  
public class HashSetCollectionServicesInJava {
      
    public int addAuthorsViaHashSet(Set authorSet) 
    {
        GeekAuthor rachel = new GeekAuthor("Rachel", 1, "Java", 200);
        GeekAuthor monica = new GeekAuthor("Monica", 1, "Python", 100);
        GeekAuthor phoebe = new GeekAuthor("Rachel", 1, "Java", 200);
        authorSet.add(rachel);
        authorSet.add(monica); 
        authorSet.add(phoebe);
        return authorSet.size();
    }
    public int getAuthors(HashSet authorsSet) {
        return authorsSet.size();
    }
      
    public String getAuthorName(HashSet author,GeekAuthor geekAuthor) {
        if (author.contains(geekAuthor)) {
            // Mapping the retrieved value
            return geekAuthor.getAuthorName();            
        }
        return null;
    }
}

Хорошо, теперь давайте проверим это. Нам нужно проверить, верны ли наши предположения. т.е. то, что происходит во время добавления хэш-карты, и то, что происходит при добавлении хэш-набора, мы можем обосновать приведенными ниже тестами.

TestCollectionServicesJava.java

Java




import static org.junit.jupiter.api.Assertions.assertEquals;
  
import java.util.HashMap;
import java.util.HashSet;
  
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
  
public class TestCollectionServicesJava {
    @DisplayName("Test check for adding geekauthors in HashMap collection ")
    @Test
    public void testCheckForAdditionOfAuthorsInHashMap() {
        HashMap<String,GeekAuthor> authors = new HashMap<String,GeekAuthor>();
        HashMapCollectionServicesInJava hashMapCollectionServicesJavaObject = new HashMapCollectionServicesInJava();
        assertEquals(true, hashMapCollectionServicesJavaObject.getAuthors(authors) == 0);
        // adding few authors
        hashMapCollectionServicesJavaObject.addAuthors(authors);
        // "Rachel" key is duplicated and hence we expect only 2
        assertEquals(true, hashMapCollectionServicesJavaObject.getAuthors(authors) == 2);
        // "Rachel" key is duplicated, now lets assert that the 
        // last taken value is updated for "Rachel" key
        assertEquals(true, hashMapCollectionServicesJavaObject.getAuthorName(authors,"Rachel").equalsIgnoreCase("Phoebe"));
                  
    }
    @DisplayName("Test check for adding geekauthors in HashSet collection ")
    @Test