-3

I'm trying to create a method where it outputs a certain number of stars based on the rating of a movie. I'm using the toString method, but am unsure of how to call this in my tests. When I attempt to write the tests, it says that "Non-static method cannot be referenced from a static context". I'm trying to use assertEquals to see if it's outputting the desired result with "assertEquals("***", Rating.toString());". My other methods had the same problem so I made them static, but this is not an option with the toString method. Is it acceptable to simply make the other methods static, or is the message likely hinting at a different flaw (or flaws) in my methods and/or tests? This may actually result in the same answer if it's a bigger problem within the code, but how would I go about testing toString when it gives the same message (non-static method cannot referenced..) when toString cannot be static?

I have reviewed other questions about the toString method and testing, but am having trouble relating it to my own code. Also, I'm not sure if I'm dealing with one error or multiple which is making it a difficult problem to solve. Help would be very much appreciated.

public class Rating {

    public static int votes;
    public static double score;
    public static String result;


    public Rating() {
        votes = 0;
        score = 0;
    }

    public static void resetVotes(){
        Rating.votes = 0;
        Rating.score = 0;
    }

    public static int getNumVotes(){
        return Rating.votes;
    }

    public static void addVote(double rating){
        Rating.votes = Rating.votes + 1;
        Rating.score = Rating.score + rating;
    }

    public static double computeScore() {
        return (Rating.score / Rating.votes);
    }


    public String toString() {

        if (Rating.votes > 1)
        {
            if (computeScore() > 1 && computeScore() < 2)
            {
                result = "*";
            }
            else if (computeScore() > 2 && computeScore() < 3)
            {
                result = "**";
            }
            else if (computeScore() > 3)
            {
                result = "***";
            }
            else if (computeScore() < 1)
            {
                result =  " ";
            }
        }

        return result;
    }
Jennifer
  • 3
  • 4
  • 1
    declare result within the toString method. why would you need anything static? – Stultuske Feb 08 '18 at 10:34
  • You don't even really need that `result` variable, you can just return within the `if` blocks and then return a default value at the end. What's the actual error you're seeing? Surely the compiler is telling you simply that you don't have a `result` variable. What does this have to do with any "test"? – David Feb 08 '18 at 10:35
  • Just change your `public static String result;` to `public String result = "";`. Or better, remove it and add `String result = "";` at the start of your toString(). – Turtle Feb 08 '18 at 10:39
  • <> your code is no different than a normal code and overriding the toString method and putting this code is not making any logic here – Suresh Feb 08 '18 at 10:40
  • The instructions for my assignment simply said to create a method called toString - They tell us what to name all of our methods so I wasn't aware that this was supposed to be any different. I've tried to look up how it's supposed to be used, but I'm not really getting it. It has to be the toString method and it has to return a string. I'm attempting to write tests for this, and I'm trying to use assertEquals to confirm that the result is the string I want. I'm not sure how to put that result in assertEquals. – Jennifer Feb 08 '18 at 10:45
  • Possible duplicate of [Java: when to use static methods](https://stackoverflow.com/questions/2671496/java-when-to-use-static-methods) – Turtle Feb 08 '18 at 10:46
  • Just to note: if `computeScore()` is exactly `2` or `3`, you don't have a default `else`. – achAmháin Feb 08 '18 at 10:47
  • @JenniferM Can you post your entire class? At least the relevant parts: class name, constructor, attributes, and related methods. If your class is `Movie`, then you probably miunderstood the "You must use toString" part. – Turtle Feb 08 '18 at 10:48
  • Just posted it all, my class is Rating. – Jennifer Feb 08 '18 at 11:02
  • @JenniferM: You keep mentioning "tests" and "assertEquals", but none of that is reflected in the code you're showing us. What is the actual problem? How *specifically* is your code failing? If the compiler is giving you an error, *read the error*. What does it tell you? Also, why are all these methods `static` in the first place? Semantically "toString" returns a string representation of an object instance. But your object has no instance state. – David Feb 08 '18 at 11:10
  • The tests are in a different class, in another package. All of the methods are static because I kept getting the message "Non-static method cannot be referenced from a static context." Putting static in the methods made 9/10 of my tests pass, except for the test for the toString method. At this point, I don't really have anything to post for that test to show you. I've tried multiple different things and none of them worked. I don't believe my method is correct, and I'm not sure how to correct it and create a test that works with it. – Jennifer Feb 08 '18 at 11:22
  • 1
    @JenniferM: Well, randomly adding/removing the `static` keyword until the code compiles is certainly no way to correct anything. The `static` keyword has a very specific meaning, and if that meaning doesn't match what you're trying to write then you shouldn't use it. Regardless, you still haven't described any actual problem here. Focus on the specific problem you're trying to solve right now. What *specifically* is failing? What is the actual error or unexpected behavior you're observing? "I can't get it to work" isn't an answerable question. – David Feb 08 '18 at 11:29
  • David, thanks for trying to help. I've already stated what message I was getting from the tests. My "none of them worked" comment was to emphasize how lost I am when it comes to the tests for toString. The method works differently than the rest (or is supposed to), which I didn't initially expect, and I don't believe I really have anything to go off of. While I definitely don't want to make a habit out of just removing/adding things for the sake of it, it's almost 4 am and my assignment is due at 9 am. If the tests don't pass, I get a zero. However, they do pass as is. – Jennifer Feb 08 '18 at 11:42
  • @Jennifer: *"However, they do pass as is."* - So your code is now working? If the solution provided below was what you needed, please mark it as such. Or if the solution wasn't what you needed but you've otherwise solved the problem, please post your solution so that others may be helped in the future. – David Feb 08 '18 at 12:30
  • @David When I said they pass as is, I meant all of the tests besides the ones for toString. Thanks for the help! The solution below did help, I just marked it. – Jennifer Feb 08 '18 at 18:38
  • I clarified my question so the problem (hopefully) makes sense to anyone else who reads this now. – Jennifer Feb 08 '18 at 20:06

2 Answers2

1

There is no reason to have any static variables or methods here.

What probably happened is that you called your tests this way:

AssertEquals(Rating.getNumVotes(), 5);
Rating.addVote(5.5d);
AssertEquals(Rating.getNumVotes(), 6);
AssertEquals(Rating.computeScore(), 42);

What this means is that you have only one Rating, the one you're modifying. What you want to do is create an instance of this class, that will represent a specific Rating. So your test should look like this:

Rating r1 = new Rating(); //An instance of Rating
r1.addVote(4.3d);
r1.addVote(4d);
r1.addVote(2.5d);
r1.addVote(5d);

Rating r2 = new Rating(); // Another instance of Rating
r2.addVote(4d);

AssertEquals(r1.getNumVotes(), 4);
AssertEquals(r2.getNumVotes(), 1);

And your Rating class should look like this:

  • I deleted the statics, and changed the toString() method to make it simpler. Check that I got the good number of stars though, as I'm not sure if a 2.5 movie is 2-star or 3-star.

  • Notice the @Override on top of the toString() ? This means this method is inherited, I suggest you look it up. This has no impact on your actual code.

  • You see the this keyword? it refers to the current instance of the class: when you add a vote for example, you incerement the number of vote of this specific rating, not of all ratings, as you did with the static.

    public class Rating {
    
    public int votes;
    public double score;
    public String result;
    
    
    public Rating() {
        votes = 0;
        score = 0;
    }
    
    public void resetVotes(){
        this.votes = 0;
        this.score = 0;
    }
    
    public int getNumVotes(){
        return this.votes;
    }
    
    public void addVote(double rating){
        this.votes = this.votes + 1;
        this.score = this.score + rating;
    }
    
    public double computeScore() {
        return (this.score / this.votes);
    }
    
    @Override
    public String toString() {
      String result;
      double score = computeScore();
      if (this.votes > 1)
      {
        if (score <= 0)
            result = "";
        else if (score <= 1)
            result = "*";
        else if (score <= 2)
            result = "**";
        else if (score <= 3)
            result = "***";
        else
            result =  "****";
       }
       else
            result = "No votes.";
    
       return result;
     }
    }
    
Turtle
  • 1,626
  • 16
  • 26
  • Does m have to be someone in the toString method? – Jennifer Feb 08 '18 at 10:54
  • The meaning of static may have contributed to my problem, but my main problem is not knowing how to use the toString method and how to go about writing tests for it and using the return string in assertEquals. I saw previous answers like yours, and have tried creating an instance of the class but it still seems to be missing something because the test is failing. – Jennifer Feb 08 '18 at 11:05
  • 1
    @JenniferM Now that you updated your question, I can see that this is a different problem. But for reference, note that in your class, you could (and actually should) remove all the static keywords. They serve no purpose and actually cause your code to be flawed. – Turtle Feb 08 '18 at 11:12
  • When I didn't have it I was getting the message "Non-static method cannot be referenced from a static context" for my tests. When I put that in, all of them passed. – Jennifer Feb 08 '18 at 11:25
  • @Jennifer Here ya go. Leave me a comment if you have questions about somthing I wrote and you can't find an explanation, I'll add the details ^^ – Turtle Feb 08 '18 at 13:03
  • This makes so much more sense. Thank you! – Jennifer Feb 08 '18 at 18:36
0

You can do this:

public class yourclass {
    public static String toString(bool votes, int computeScore ) {

        if (votes)
        {
            if (computeScore > 1 && computeScore < 2)
            {
                result = "*";
            }
            else if (computeScore > 2 && computeScore < 3)
            {
                result = "**";
            }
            else if (computeScore > 3)
            {
                result = "***";
            }
            else if (computeScore < 1)
            {
                result =  " ";
            }
        }

        return result;
    }
}

then you can call that in your test somethin like that

assertEquals(yourclass.toString(true, 1), "*"))
assertEquals(yourclass.toString(true, 2), "**"))
assertEquals(yourclass.toString(true, 3), "***"))
assertEquals(yourclass.toString(true, 4), "***"))
usr4217
  • 420
  • 4
  • 18
  • This is probably a bad idea to change the `toString()` method, as it is an inherited method from `Object`. – Turtle Feb 08 '18 at 13:04