i am trying to test that a method creates an object. i have it almost working using PowerMockito.verifyNew().withArguments() however, the Arguments that are passed to the constructor are an object and an ArrayList of objects. the output of the test is:
Actual
invocationSubstitute.performSubstitutionLogic(
1,
6,
11,
13,
[au.edu.sccs.csp3105.NBookingPlanner.Person#2449cff7],
au.edu.sccs.csp3105.NBookingPlanner.Room#62da83ed,
"description"
);
Expected
invocationSubstitute.performSubstitutionLogic(
1,
6,
11,
13,
[au.edu.sccs.csp3105.NBookingPlanner.Person#40bffbca],
au.edu.sccs.csp3105.NBookingPlanner.Room#42a9a63e,
"description"
);
i can see that the problem is the objects are the same type but not the same object, is there a way of saying the Expected object is of the correct type?
test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Planner.class, Meeting.class})
public class MonthInput {
Planner planner;
#Rule
public final TextFromStandardInputStream systemInMock = emptyStandardInputStream();
#Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
#SuppressWarnings("deprecation")
#Before
public void setup() throws Exception {
Meeting meetingMock = Mockito.mock(Meeting.class);
PowerMockito.whenNew(Meeting.class).withAnyArguments().thenReturn(meetingMock);
}
#Test
public void MonthInputofless5() throws Exception {
// make spy
planner = Mockito.spy(Planner.class);
//override main menu with do nothing
Mockito.doNothing().when(planner).mainMenu();
//provide inputs
systemInMock.provideLines("1","6","11","13","ML13.218","Mark Colin","done","description");
//set expected outputs
ArrayList<Person> attendees = new ArrayList<Person>();
attendees.add(new Person("Mark Colin"));
Room where = new Room("ML13.218");
//call the method
planner.scheduleMeeting();
//set passing terms
PowerMockito.verifyNew(Meeting.class).withArguments(1,6,11,13,attendees,where,"description");
}
Fix your code
A verify simple fix on your classes: implement hashCode and equals on Person and Room so Powermock verification can actually compare two objects for equality and not just rely on the object reference.
Fix your tests
If you don't want to fix your code, but the test, you could either use a Mockito matcher (i.e. org.mockito.Matchers.eq or org.mockito.Matchers.any). But please note, that eq relies on equals and won't work unless you implement it (see above). But any would match any object of that type (surprise!)
PowerMockito.verifyNew(Meeting.class)
.withArguments(eq(1),eq(6),eq(11),eq(13),
any(List.class),
any(Room.class),
eq("description"));
If the actual value matters, you could use an ArgumentCapture instead of a matcher and check the captured value.
Theoretically, it should look like this:
final ArgumentCaptor<Person> personCaptor = forClass(Person.class);
final ArgumentCaptor<Room> roomCaptor = forClass(Room.class);
PowerMockito.verifyNew(Planner.class)
.withArguments(eq(1),eq(6),eq(11),eq(13),
personCaptor.capture(),
roomCaptor.capture(),
eq("description"));
final Person passedParam = personCaptor.getValue();
//do your comparison here
But I didn't get the capture example running, so maybe that's only possible with plain Mockito.
Just don't!
All that said, you should verify your overall approach. Using Whitebox-Testing may create very brittle tests and won't help much in refactoring and may further foster bad class design.
The imprudent use of Powermockito is an anti-pattern. It's a very mighty tool for testing the untestable, i.e. badly designed legacy code from the dark ages of the internet where the homepages were handcrafted HTMLs and full of wobbly GIFs.
Don't use it for new, greenfield projects. Just don't.
Instead try focusing on the observable result of any action. Invoking the scheduleMeeting() method may produce any result that is more easy to check - it's the result that matters, not the way to get they. Trust me, not a single user gets happier when a constructor was called.
Results could be
an instance of a meeting (as return value, that would be best in your example)
a state change in the planner (any getters?)
a state change in a downstream service / db
a written file
an output written to System.out
Related
I am a new Junit Learner I would like to test my code according to 2 list class. However I never saw any example of that.
My real code is below :
public static List<JourneyType> applyFilter(List<JourneyType> journeyList, List<AvailabilityFilterOptionType> filterOptions)
{
List<JourneyType> filteredJourneyList = new ArrayList<>();
filteredJourneyList = applyStopFilters(journeyList, filterOptions);
filteredJourneyList = applyCarrierFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyRbdFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyDurationFilter(filteredJourneyList, filterOptions);
return filteredJourneyList;
}
and my test scenario :
#Test
public void testApplyFilter()
{
fail("Not yet implemented");
}
Thank you in advanced
Actually, this is pretty simple.
#Test
public void testApplyFilter()
{
assertThat(someObject.applyFilter(journies, filters), is(expectedOutcome));
}
In other words: you know what this method is supposed to do. ( Well, such knowledge is the prerequisite for testing stuff. When you don't know what your code is doing, there is no point in verifying its correctness via testing...)
As in: given some known input data, you should be able put down an expectation about output coming back. And that is what you check for.
Of course, the tricky part could be to correctly identify dependencies, and mock them where needed.
But ideally, your test should just be that: testing the public contract of your method under test. Something goes in, and you check that the output coming back meets your expectations. Ideally, you have to mock nothing for such tests, because you do not at all rely on testing implementation details. You only test the public contract "given this input, this is the expected output".
( where: assertThat() is just a different type of assert, and is() is a hamcrest matcher. There are many other hamcrest matchers, such as containsInAnyOrder() (that one is really neat if you don't care about the order of elements returned, but one has to understand that is used slightly different, it would need containsInAnyOrder(expectedOutcomeList.toArray()) methinks )
I have written to Unit test - junit with Mockito library to test any methods, who save to databases new account - addNewAccount methods.
I would like to ask - if I need to add a method or what and how - to delete/remove an account, whos was added. and please show me what I can do it.
my unit test is:
#Test
public void shouldSaveaAccountToDb() {
Account acc = new Account();
acc.setUser(this.user);
acc.setEmail(this.mail);
String account = this.accountController.addNewAccount(this.user, this.mail);
verify(this.accountRepepetytory)).save(Mockito.refEq(acc, new String[0]));
Assert.assertThat(account, CoreMatchers.is("Account"));
}
I also want to add a case with a null value and testing null and empty string. if you can any idea to add test case please tell me.
thank you very match for help. I improved my test.
I have also a method who testing with null value. This is the method.
#Test
public void SaveToDatabaseWithNull() {
Account acc = new Account();
String mail = null;
user.setMail((String)mail);
user.setUser(this.user);
String account = this.accountController.addNewAccount(this.user, (String)mail);
verify(this.accountRepetytory)).save(Mockito.refEq(uaccount, new String[0]));
Assert.assertThataccountCoreMatchers.is("Account"));
}
I also would like to ask, whether in these tests it is necessary to delete some values, adding a method that deletes the account. if I create an account in one method, do I have to delete it in some way and in which way? to test correctly with the null value in the later method.
In your code you have some weaknesses that make you test britle and hard to understand:
Each test method should verify one single expectation only.
Your test verifies two things:
The code created an object of class Account that equals to the one created in the test method by the means of the Account classes implementation of equals().
The return value of the method is a string with content "Account".
Problem of that is that the test does not explain why you expect that string.
So basically you should have separate methods to verify either behavior allowing for a better description of the tested behavior in the test method name.
reduce dependencies to unrelated code.
Mockito.refEq() relies on a (correct) implementation of the equals method in class Account. There is no quaratee that this method is actually implemented or (even worse) may need addioional configuration in future if an account gets more properties that are not allowed to be null.
The better way here is to use an ArgumentCaptor and verify the properties of the captures object:
#Test
public void shouldPassAnAccountObjectWithNameAndEmailSetToDB() {
ArgumentCaptor<Account> accountCaptor =
ArgumentCaptor.forClass(
Account.class);
this.accountController.addNewAccount(
this.user,
this.mail);
verify(this.accountRepepetytory))
.save(
accountCaptor.capture());
Assert.assertThat(
"user",
accountCaptor.getValue().getUser(),
CoreMatchers.is(this.user));
Assert.assertThat(
"email",
accountCaptor.getValue().getEmail(),
CoreMatchers.is(this.email));
}
I am new to JUnit, and do not know which methods should have tests and which should not. Take the following example:
public List<Site> getSites(String user)
{
SiteDao dao = new SiteDaoImpl();
List<Site> siteList = new ArrayList<Site>();
ServiceRequest rq = new ServiceRequest();
rq.setUser(user);
try
{
ServiceResponse response = siteDAO.getReponse(rq);
List<String> siteNums = response.getSiteNums();
if (siteNums != null && !siteNums.isEmpty())
{
List<DbModelSite> siteInfo = dao.getSiteInfo(siteNums);
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = SiteMapper.mapSites(siteInfo);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return siteList;
}
public static List<Site> mapSites(List<DbModelSite> siteInfo)
{
List<Site> siteList = null;
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = new ArrayList<Site>();
for (DbModelSite temp : siteInfo)
{
Site currSite = mapSite(temp);
siteList.add(currSite);
}
}
return siteList;
}
public static Site mapSite(DbModelSite site)
{
Site mappedSite = null;
if (site != null)
{
mappedSite = new Site();
mappedSite.setSiteNum(site.getSiteNum());
mappedSite.setSpace(site.getSpace());
mappedSite.setIndicator("Y");
}
return mappedSite;
}
It is pretty trivial to come up with a unit test for both the mapSites() and mapSite()methods, but where I am having trouble is with the getSites() method. Does it make sense to unit test this method? If so, how would I go about doing so? It seems that this would require quite a bit of mocking, and as I am very new to JUnit, I have not been able to figure out how to mock all of these objects.
So my question is really two fold:
How do you determine if a method needs to be unit tested?
How does one unit test a complex method which requires a large amount of mocking?
Yes, it makes sense to test that method.
The first thing to be able to test it, would be to use dependency injection. If the method creates its own SiteDao instance using new, there is no way you can tell the method to use another, mock instance of SiteDao.
So, read on dependency injection, and use it. Basically, it boils down to
public class MyService {
private SiteDao siteDao;
public MyService(SiteDao siteDao) {
this.siteDao = siteDao;
}
// use the siteDao passed when constructing the object, instead of constructing it
}
That way, when testing your service, you can do
SiteDao mockSiteDao = mock(SiteDao.class);
SiteService service = new SiteService(mockSiteDao);
Here's one pice of advice that is not directly related to your question, but will make your code much simpler, and thus easier to test, too:
Never return null from a method returning a collection. Return an empty collection to signal "no element".
In general, don't accept null as a valid method argument value, especially if the argument is a collection.
Corollary of 1 and 2: by following these principles, you never need to check for null or emptyness of a collection. Just use it directly.
This will reduce the number of if (siteNums != null && !siteNums.isEmpty()) cluttering your code, and you'll have way fewer branches to test, too.
Note that all sane libraries (the JDK methods, JPA, etc.) follow these principles. A JPA query will never return a null list for example.
Also, don't swallow an exception by just printing its stack trace and returning an empty list, as if nothing bad happened. Let the exception propagate so that you can notice and fix the bug.
Just imagine that this method is a method returning the number of cancer tumors found by a medical analysis system. Would you really like the system to tell you that you're in perfect health, whereas the system was in fact unable to do its job due to an exception? I would really prefer the system to say "I'm out of order, use another machine to be sure".
The idea of unit testing is to ensure that each "unit" (which is usually a method) can be tested in isolation so you can test that for given input you receive an expected output, so to answer your questions:
I should say all public methods should be unit tested
If you are doing too much in your method that you need to mock lots then you probably want to break the functionality out into another class
Going back to your example there are a couple of things to be wary of if you want to unit test:
new - anytime you use this keyword in a method you will find it difficult to mock that object. In some cases (like ServiceRequest) it's fine but in others such as SiteDao you'll have problems.
Static methods - same thing, with SiteMapper.mapSites(siteInfo) you will find it difficult to mock
You can use libraries such as PowerMock to mock new, private and static methods but I personally try to avoid that.
I am learning unit tests (in a TDD-like approach).
I am creating a class that encapsulates an collection, it has 3 methods:
store
retrieveAllDocuments
hasItem
I created one test: testRetrieveWhenEmpty, whici goes like this:
#Test
public void testRetrieveAllDocumentsWhenEmpty() {
List<String> storedDocs = state.retrieveAllDocs();
assertNotNull(storedDocs);
assertEquals(0, storedDocs.size());
}
And then I made it pass.
Now I would like to create a testRetrieveAllDocumentsWhenNotEmpty, which would be like this:
#Test
public void testRetrieveAllDocumentsWhenNotEmpty() {
state.store("test") //This is the only api point that I can use to insert things
List<String> storedDocs = state.retrieveAllDocs();
assertNotNull(storedDocs);
assertEquals(1, storedDocs.size());
assertEquals("test", storedDocs..get(0));
}
But now I have to implement the store method, so I created the following test method:
#Test
public void testStoreDocument() {
state.store("test")
List<String> storedDocs = state.retrieveAllDocs(); //This is the only api point I can use to see the content
assertNotNull(storedDocs);
assertEquals(1, storedDocs.size());
assertEquals("test", storedDocs.get(0));
}
I see two problems:
These methods are identical.
I test two methods in each test, if the store fails, I get a message that the retrieve has a problem.
Using reflection would bind my test to my implementation, and I am trying to avoid it.
Changing the interface for better testing is hard to argument to my team mates.
What approach do you take in these cases? (Is this case a problem at all?)
You could try shifting your view from writing "a (set of) tests per method" to "a test per useful behaviour" of the class you are testing.
If this class is both reader and writer of the data, it kinda makes sense to use its insert operations when testing the retrieval behaviour and vice versa.
I'd test the no items, one item, multiple items, has a specific item, does not have a specific item cases. These tests would implicitly test the store method as well.
Kevlin Henney's talk programming with GUTs provides a good explanation about this concept.
Actually does not need to be equals:
In testRetrieveAllDocumentsWhenNotEmpty you can add more than one document then check size, also you don't need to get all individual documents, you need to assert size is the correct.
This method asserts to get ALL documents in a non empty scenario, if you can assert you inserted 3, AND as long the testStoreDocument exists, you don't need to assert the document retrieve but yes the list size to know if ALL are returned.
#Test
public void testRetrieveAllDocumentsWhenNotEmpty() {
state.store("test1")
state.store("test2")
state.store("test3")
List<String> storedDocs = state.retrieveAllDocs();
assertNotNull(storedDocs);
assertEquals(3, storedDocs.size());
}
In testStoreDocument, you need to get the document, you don't need to assert the size of stored documents.
#Test
public void testStoreDocument() {
state.store("test")
List<String> storedDocs = state.retrieveAllDocs(); //This is the only api point I can use to see the content
assertNotNull(storedDocs);
assertEquals("test", storedDocs.get(0));
}
As mention before try to write your unit tests in a way they test scenarios. Every reader understands then better what you class is for. Since we do not just want to use a method, we want to achieve something with this method.
You can express this in the name of your tests like this: when{SomethingHappens}Then{ThisIsExpected} or given{Situation}Should{BeHandledInThisWay}
You could create tests like givenStoredDocumentsShouldBeAllReturned and whenDocumentIsStoredThenItCanBeRetrieved
I could not get it to work. It's like the method is not mocked.
Are there alternative groovy testing frameworks that work better to mock static Java methods?
Update 02/Mar/2011: Adding code:
I am actually trying to mock the Scala XML.loadXml (I am trying Groovy for unit testing) class:
This is my test case:
// ContentManagementGatewayTest.groovy
class ContentManagementGatewayTest extends GMockTestCase
{
void testGetFileList()
{
// Preparing mocks code will go here, see below
play {
GetFileGateway gateway = new GetFileGateway();
gateway.getData();
}
}
}
// GetFileGateway.scala
class GetFileGateway {
def getData()
{
// ...
val xmlData = XML.loadData("file1.txt");
}
}
I tried testing using both gmock and metaClass:
// metaClass:
XML.metaClass.'static'.loadFile = {file ->
return "test"
}
// gmock:
def xmlMock = mock(XML)
xmlMock.static.loadFile().returns(stream.getText())
You can do this using Groovy (metaprogramming), you don't need any additional libraries. Here's a (stupid) example, that overrides Collections.max such that it always returns 42. Run this code in the Groovy console to test it.
// Replace the max method with one that always returns 42
Collections.metaClass.static.max = {Collection coll ->
return 42
}
// Test it out, if the replacement has been successful, the assertion will pass
def list = [1, 2, 3]
assert 42 == Collections.max(list)
Update
You mentioned in a comment that my suggestion didn't work. Here's another example that corresponds to the code you've shown in your question. I've tested it in the Groovy console and it works for me. If it doesn't work for you, tell me how your testing differs from mine.
Math.metaClass.static.random = {-> 0.5}
assert 0.5 == Math.random()
Scala doesn't have static methods, so it is no wonder you couldn't mock one -- it doesn't exist.
The method loadXml to which you refer is found on the XML object. You can get that object from Java with scala.XML$.MODULE$, but, since objects are singleton, its class is final.
Alas, loadXML is defined on the class XMLLoader, which the object XML extends, not on the object XML itself. So you can simply do a normal mock of XMLLoader. It will lack a few methods, but perhaps it will do all you need.
The documentation for GMock seems to show that you can just do:
Mocking static method calls and
property call is similar to standard
method calls, just add the static
keyword:
def mockMath = mock(Math)
mockMath.static.random().returns(0.5)
play {
assertEquals 0.5, Math.random()
}