问题
I am writing a simulation of Bananagrams. Currently, I have a GameMaster
class that maintains the common collection of pieces. The deal(Player)
method deals a certain number of pieces to that player.
I want to write unit tests for this. However, at this point, I have no getters, and thus no way to check the status of the objects.
Why not add getters? I don't want to add code to the public interface only for testing. Right now, there is no other reason to expose those functions.
What am I supposed to do here? Add the getters anyway, cluttering the public API (or hoping that they will be needed in the future)? Forgo unit testing? (Sounds like a bad idea.)
Or, does this indicate that my public interface is flawed?
回答1:
Instead of relying upon a concrete instance of a Player, write your unit tests to an interface (or the equivalent), and rely upon mocks or other interaction to validate not that the player is in the correct state, but simply that the correct calls (from the view of the GameMaster class.
If you cannot validate correct behavior of the GameMaster class without relying upon validating the end state of the Player, that's a sign that your responsibilities are misplaced. The GameMaster should be responsible for telling the Player what happened, while the Player should be responsible for taking the appropriate action.
This is also a benefit, as it means that the tests for the GameMaster will be dependent only on the behavior of the GameMaster class, and will not need to be touched if the Player class changes its behavior.
Avoid adding getters for unit tests. When you're tempted to add a getter, look instead at using interaction testing (as I just described) instead of state-based testing.
回答2:
There are more than one means of verifying that a piece of code works. The first one most of us think of is state based testing (ie, using getters to verify that your object's final state is what you think it should be). However, another way of verifying that your code works is to use behavior or interaction based testing.
Martin fowler has a decent article about the difference here
回答3:
You should test the functionality that is internally using these state holding variables. If no public functionality is using them, then they are dead code.
回答4:
I'd say that your classes may be doing too much. It sounds like you have them storing state AND doing other stuff.
Consider what would make them easier to test. How you would test them if you split the state and logic apart? Instead of just calling
GameMaster gameMaster = new GameMaster;
playerOne.Score = gameMaster.ComputePlayerScore(newScore);
you'd pass the state-only instance of GameState into the constructor of the GameMaster routine:
GameState gameState = new GameState;
GameMaster gameMaster = new GameMaster(gameState);
playerOne.Score = gameMaster.ComputePlayerScore(newScore);
Then your unit test routines can pass in whatever data they need for gameState and newScore, and check the results in gameState after it returns. Dependency Injection is your friend.
回答5:
One thing you could do is subclass your main class to provide the getters for testing. This would be easier if you had interfaces to work with.
Subclassing to provide getters is a semi-dangerous proposition. If you are simply providing getters for internal properties the damage will be minimal, but you need to be careful that you are testing the actual class and not your derived version.
回答6:
I see nothing wrong with adding code specifically for testability. Unit tests are invaluable for regression testing.
However, it's also correct that it shouldn't affect your public API. Therefore, I suggest making the getters package-protected, and placing your unit tests in the same package as the Player
class. (In a different source folder though, so that you have clean separation between production code and test code.)
回答7:
unit tests don't make your code better , they make your whole application more stable over time with changes and added features. this is why if you do not have public getters in your GameMaster class you do not need to create them for unit tests.
no getters does not mean your interface is flowed ,test driven development concept is write minimum code to pass a test ( that comes from a requirement ) , if you don't needem you don't writem . print, trace, log will be here long after unit tests vanish ( ok they are also here to stay , but in many cases overated and overused )
回答8:
What am I supposed to do here? Add the getters anyway, cluttering the public API (or hoping that they will be needed in the future)?
I don't get this response. How is a getter "clutter"?
You're doing Test Driven Development. The design is driven by the absolute need to test everything.
Getters aren't "clutter". They're how you test things.
"Forgo unit testing?"
I don't think this is a good idea.
来源:https://stackoverflow.com/questions/1962735/balancing-design-principles-unit-testing