I have one doubt about How to name test method, becuase I Lastly have doing unit test to a big project, and based in my experience I think that I am set name test method bad or worse, Here an example about my code.
public function notificationApproved(Request $request, User $user) {
$user = $user->getId();
$request = $request->getRequest();
$this->notification = $this->em->getRepository('AppBundle:Notification')->find(Notification::APPROVED);
$this->notificationCategory = NotificationCategory::APPROVED;
$this->notificationStatus = $this->em->getRepository('AppBundle:NotificationStatus')->find(1);
$this->reason = $reason;
//notification approvers project
foreach ($projectHasUserUnits as $keyData => $valueData) {
$projectUserUnitResponsability = $valueData->getProjectUserUnitResponsability()->last();
$responsability = $projectUserUnitResponsability->getResponsabilityProject();
if (is_null($projectUserUnitResponsability->getEndAt()) && ($responsability->getId() == Responsability::TYPE_RESPONSIBLE || $responsability->getId() == Responsability::TYPE_ACCOUNT_MANAGER || $responsability->getId() == Responsability::TYPE_PROJECT_MANAGER)) {
$user = $valueData->getUserHasUnit()->getUser();
if( !in_array($user,$this->users)){
$this->users[] = $user;
$description_label = 'notification_description_project_50';
$short_description = 'notification_content_project_50';
$notification = $this->generateNotification($Project, $user, $description_label,$short_description);
if ($notification) {
$this->notificationTrigger
->sendProjectNotification($user, $notification, $Project
, $notification->getDescription(), date('l m-d-y H:i a'));
}
}
}
}
}
it is a big method, I know, but don't worry for its logic, Just see the conditionals, and think how to name a method test like this, In this case, when itself come in all conditionals... maybe:
test_notificationApprovedWhenAllConditionsAreTrue
test_notificationApprovedWhenProjectHasUserUnitsIsBiggerThanZeroAndProjectUserUnitResponsabilityGetEndAtIsNotNullAndResponsabilityGetIdIsEqualToResponsabilityTYPERESPONSABILITYorResponsabilityGetIdIsEqualToResponsabilityTYPE_PROJECT_MANAGERanduserInArrayIsTrueAndNotificationIsTrue...
You only imagine read that !
However when it come only one conditional is easier that the above, !Of Course!, like this:
test_notificationApprovedWhenProjectHasUserUnitsIsBiggerThanZeroAndProjectUserUnitResponsabilityGetEndAtIsNotNullAndResponsabilityGetIdIsEqualToResponsabilityTYPERESPONSABILITYorResponsabilityGetIdIsEqualToResponsabilityTYPE_PROJECT_MANAGER
I've tried with comments inside test, but If a test fail, the idea would be guiding for its name (to fix the error rapidly)
So, do you have any idea ?
I have good experience with given<one-or-more-conditions>_action_result naming of test methods. Just a simple example for your case:
test_givenUserUnitGreaterThanZeroAndProjectIdEqualToOne_whenApproveNotification_thenNotificationIsSent()
I've simplified things for the sake of readability but you get the point. This nomenclature is taken from behavior-driven test frameworks. In languages that do not need the test_ you can save it.
Tests are really good indicators for code quality. Generally speaking if writing unit tests is easy then it's because the code to test is of "good" quality. You can follow some simple guidelines:
List every precondition exactly as it is necessary for the use case
Exactly one action. If not make multiple tests.
Exactly one result. If not extract methods and test them separately.
If method names get too long because of many preconditions then it might be time to extract a new class because this one has too many responsibilities
A bit of advice: if you'd add a test annotation, you would not need to prefix method names with test.
/**
* #test
*/
function givenThis_producesThat () {
Related
I have written a code part of which is as below
Object Cal{
def mergedatasets(df: Dataset[Row], df1: Dataset[Row],df2: Dataset[Row]):Dataset[Row]={
df.union(df1).union(df2)
//other logic
}
}
object readDataframes{
def readFirstDF(spark:SparkSession):Dataset[Row]={
spark.read.json(somefile)
}
def readSecondDF(spark:SparkSession):Dataset[Row]={
spark.read.json(somefile)
}
def readThirdDF(spark:SparkSession):Dataset[Row]={
spark.read.json(somefile)
}
}
In the above code I am reading 3 files and then merging them into one which I use further for processing.
Based on the above scenario my questions are as follows:
Does it make sense to Unit test the function mergdatasets? If yes, What are the basic/minimal things to test for?How to check for corner cases, if any?
Does it make sense to Unit test readDataframes?If yes what to test for ?Would it be to check if inferred schema is as expected? and anything else?
I would like to extend the above questions for the following functions too
def timeIntervalAgg(df: Dataset[Row]): Dataset[Row] = {
val timeInterval = df
.groupBy("id","page_number")
.agg(sum("timeInterval").alias("timeInterval"))
timeIntervalAgg
}
def timeInterval(df: Dataset[Row]): Dataset[Row] ={
val windowSpec = Window.partitionBy("id").orderBy("date_time")
val timeFmt = "yyyy-MM-dd'T'HH:mm:ss"
val endTime = lead(col("date_time"),1).over(windowSpec)
val startTime = col("date_time")
val timeDiff = (unix_timestamp(endTime, timeFmt)
- unix_timestamp(startTime, timeFmt))
val timeInterval = df
.withColumn("timeInterval", lit(when(col("event") === "this_event",lit(null)
.cast("long"))
.otherwise(timeDiff)))
.where("""event != "this_event" """)
timeInterval
}
def addOddpages(df: Dataset[Row]) :Dataset[Row] = {
val odd = df
.where("""view_mode = "twin" """)
.withColumn("page_odd", col("page") + 1)
.drop("page")
.select(col("id"), col("date_time")
.cast("timestamp"),col("page_odd")
.alias("page"), col("page_view_mode"),
col("event"),col("timeInterval"))
val timeIntervalWithoddPage = df.union(odd)
timeIntervalWithoddPage
}
Please suggest if it is needed to refactor the code in a better way
to enable better testing.
My goal is to understand what to test for? what to look out while
writing test for code like above? All this questions are for Spark
code Unit testing not other language code testing.
How to unit test without redundantly testing spark which is already
tested?
Is it needed to test every function like this(since the logic/code is not very complicated) or is best to test the
function that combines the above functions in proper order.By doing
so can it be called unit testing?
Please feel free to share some sample Unit tests that you may write
for above code.
Read JSON files: If you just read JSON files, you don't need to test this.
In addition, it might be better to read the files with explicit schema in schema() to avoid some issues with inferred schema. Also, you do not need 3 identical methods for reading the files.
Union Datasets: Since Spark 2.3.0 there is unionByName() function.
That function resolves columns by name (not by position). You can consider the functions to avoid issues with union when your DataFrames have different order of columns. Of course, this function doesn't need to be tested. It's hard to say about the //other logic code inside the mergedatasets() method.
For unit testing, you can use ScalaTest or other tools.
Create SparkSession with master("local");
Create a DataFrame with the expected data;
Create an input DataFrame for each method you want to test.;
Compare expected and actual DataFrames;
The following project might be useful. You can find there how to compare two DataFrames. Also, there are several examples in the README: https://github.com/MrPowers/spark-fast-tests
I find it easy to write unit tests for algorithms. For example, sort(List), it is easy to write tests like:
list = [2, 1, 4];
assert(sort(list) == [1, 2, 4]);
But I find it really hard to test methods that have no logic, no if statements, just a set of calls.
There are mainly 2 examples that I'd like an answer for how to unit test them:
Example 1:
Let's say I have a class that is responsible for writing some data to a file, but that data is written in a specific way by external functions (writeHeaderToFile, writeSerializedData and writeEndOfFile).
The data is not written straight as it is to the file, so if data is something like:
{
list: [
"item 1",
"item 2"
],
name: "aaa"
}
That doesn't mean that the file will be neither the plain version of that data (without white spaces) nor it will be a simple serialized version or encrypted version into file. The actual file binary will be something unknown to me. All I know is that I can use those 3 methods to write in the right way.
This file also contains some other information that doesn't come directly from those 3 methods, like a specific type of header (that again, I have no idea how it will be represented in the file binary).
That is the class:
class FileCreator {
populateFileWithData(File file, Data data) {
doBlockWithLock(file, {
Header header;
header.format = SomeFormat;
header.version = SomeVersion;
writeHeaderToFile(file, header);
writeSerializedData(file, data);
writeEndOfFile(file);
});
}
// Private
void doBlockWithLock(File file, Lambda block) {
file.holdWritingLock();
block();
file.releaseWritingLock();
}
}
Example 2:
class Controller {
var screenOne = new ScreenOne();
var screenTwo = new ScreenTwo();
var screenThree = new ScreenThree();
void reloadButtonWasClicked() {
screenOne.reload();
screenTwo.reload();
screenThree.reload();
}
}
For this one I could do something like this:
var mockScreenOne = Mock<ScreenOne>().reload.expectOneCall();
var mockScreenTwo = Mock<ScreenTwo>().reload.expectOneCall();
var mockScreenThree = Mock<ScreenThree>().reload.expectOneCall();
Controller controller = new Controller();
controller.screenOne = mockScreenOne;
controller.screenTwo = mockScreenTwo;
controller.screenThree = mockScreenThree;
controller.reloadButtonWasClicked();
mockScreenOne.verify();
mockScreenTwo.verify();
mockScreenThree.verify();
But I don't find much value in it since I'm just asserting that I'm doing the same thing I'm doing in the implementation. Seems like code repetition to me.
What would be the proper way of testing my 2 examples?
In the first example, if you wrote the messages in question and satisfied with your test coverage, there's no reason to reproduce that testing logic on FileCreator. You just need to test the FileCreator populateFileWithData method to make sure the file is written and maybe that the locking mechanism works.
You are right, your last test is rather trivial. I'd be tempted to omit writing it. But it depends. Is it likely that someone might come along and comment out one of those panel constructors? Do you have other tests that would identify such a problem?
Let's say I have the following method in a service:
private void deleteItems(List<Item> itemsToDelete) {
def sql = new Sql(dataSource)
itemsToDelete?.each { Item item ->
sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
item.delete(flush: true, failOnError: true)
flushDatabaseSession();
}
}
How do I create a test for this method in the ItemServiceSpec? When I try it, I get either a DataSource "Must specify a non-null Connection" error or a nullPointerException on sql.
This is my existing test.
#TestFor(ItemService)
#Mock([Item])
#Build([Item])
class SubjectServiceSpec extends Specification {
...
def "delete items"() {
given:
Item item1 = Item.build().save(flush: true)
Item item2 = Item.build().save(flush: true)
Item.count() == 2
DataSource mockDataSource = Mock()
service.dataSource = mockDataSource
1 * deleteItems
when:
service.deleteItems([item1, item2])
then:
Item.count() == 0
}
}
What you are trying to do here, is to mock a dependency (DataSource) of a dependency (Sql). This normally leads to a situation, where you a not 100% aware of how the Sql interacts with the DataSource Object. If Sql changes private interaction with the Datasource in a Version Update, you have to deal with the situation.
Instead of mocking a dependency of a dependency you should the Sql Class directly. For this, the sql has to be some kind of explicit dependency that you can receive via DI or a method parameter. In this case you can just mock the execute call like so (choosen the way of a Expando-Mock, but you could also use Map or the Mock Stuff from Spock):
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock
when:
service.deleteItems([item1, item2])
then:
assertItemsAreDeletedAndTheOwnerAsWell()
Thinking about the whole testcase, there a two major problems in my opinion.
The first one is, when you ask yourself what kind of certainty do you really get here by mocking out the whole sql stuff. In this case, the only thing that you are doing here is to interact with the db. When you mock this thing out, then there is nothing anymore that you could test. There is not many conditional stuff or anything that should be backed up by a unit test. Due to this, I would suggest to write only integration spec for this test-case where you have something like a H2DB for testing purposes inplace.
The second thing is, that you actually don't need the Sql Manipulation at all. You can configure GORM and Hibernate in a way do a automatic and transparent deletion of the owner of the item, if the item is deleted. For this, look at the docs (especially the cascade part) from GORM or directly in the Hibernate docs.
To sum it up: use cascade: 'delete' together with a proper integration test and you have a high amount of certainty and less boilerplate code.
If I have a method that calls itself under a certain condition, is it possible to write a test to verify the behavior? I'd love to see an example, I don't care about the mock framework or language. I'm using RhinoMocks in C# so I'm curious if it is a missing feature of the framework, or if I'm misunderstanding something fundamental, or if it is just an impossibility.
a method that calls itself under a certain condition, is it possible to write a test to verify the behavior?
Yes. However, if you need to test recursion you better separate the entry point into the recursion and the recursion step for testing purposes.
Anyway, here is the example how to test it if you cannot do that. You don't really need any mocking:
// Class under test
public class Factorial
{
public virtual int Calculate(int number)
{
if (number < 2)
return 1
return Calculate(number-1) * number;
}
}
// The helper class to test the recursion
public class FactorialTester : Factorial
{
public int NumberOfCalls { get; set; }
public override int Calculate(int number)
{
NumberOfCalls++;
return base.Calculate(number)
}
}
// Testing
[Test]
public void IsCalledAtLeastOnce()
{
var tester = new FactorialTester();
tester.Calculate(1);
Assert.GreaterOrEqual(1, tester.NumberOfCalls );
}
[Test]
public void IsCalled3TimesForNumber3()
{
var tester = new FactorialTester();
tester.Calculate(3);
Assert.AreEqual(3, tester.NumberOfCalls );
}
Assuming you want to do something like get the filename from a complete path, for example:
c:/windows/awesome/lol.cs -> lol.cs
c:/windows/awesome/yeah/lol.cs -> lol.cs
lol.cs -> lol.cs
and you have:
public getFilename(String original) {
var stripped = original;
while(hasSlashes(stripped)) {
stripped = stripped.substringAfterFirstSlash();
}
return stripped;
}
and you want to write:
public getFilename(String original) {
if(hasSlashes(original)) {
return getFilename(original.substringAfterFirstSlash());
}
return original;
}
Recursion here is an implementation detail and should not be tested for. You really want to be able to switch between the two implementations and verify that they produce the same result: both produce lol.cs for the three examples above.
That being said, because you are recursing by name, rather than saying thisMethod.again() etc., in Ruby you can alias the original method to a new name, redefine the method with the old name, invoke the new name and check whether you end up in the newly defined method.
def blah
puts "in blah"
blah
end
alias blah2 blah
def blah
puts "new blah"
end
blah2
You're misunderstanding the purpose of mock objects. Mocks (in the Mockist sense) are used to test behavioral interactions with dependencies of the system under test.
So, for instance, you might have something like this:
interface IMailOrder
{
void OrderExplosives();
}
class Coyote
{
public Coyote(IMailOrder mailOrder) {}
public void CatchDinner() {}
}
Coyote depends on IMailOrder. In production code, an instance of Coyote would be passed an instance of Acme, which implements IMailOrder. (This might be done through manual Dependency Injection or via a DI framework.)
You want to test method CatchDinner and verify that it calls OrderExplosives. To do so, you:
Create a mock object that implements IMailOrder and create an instance of Coyote (the system under test) by passing the mock object to its constructor. (Arrange)
Call CatchDinner. (Act)
Ask the mock object to verify that a given expectation (OrderExplosives called) was met. (Assert)
When you setup the expectations on the mock object may depend on your mocking (isolation) framework.
If the class or method you're testing has no external dependencies, you don't need (or want) to use mock objects for that set of tests. It doesn't matter if the method is recursive or not.
You generally want to test boundary conditions, so you might test a call that should not be recursive, a call with a single recursive call, and a deeply-recursive call. (miaubiz has a good point about recursion being an implementation detail, though.)
EDIT: By "call" in the last paragraph I meant a call with parameters or object state that would trigger a given recursion depth. I'd also recommend reading The Art of Unit Testing.
EDIT 2: Example test code using Moq:
var mockMailOrder = new Mock<IMailOrder>();
var wily = new Coyote(mockMailOrder.Object);
wily.CatchDinner();
mockMailOrder.Verify(x => x.OrderExplosives());
There isn't anything to monitor stack depth/number of (recursive) function calls in any mocking framework I'm aware of. However, unit testing that the proper mocked pre-conditions provide the correct outputs should be the same as mocking a non-recursive function.
Infinite recursion that leads to a stack overflow you'll have to debug separately, but unit tests and mocks have never gotten rid of that need in the first place.
Here's my 'peasant' approach (in Python, tested, see the comments for the rationale)
Note that implementation detail "exposure" is out of question here, since what you are testing is the underlying architecture which happens to be utilized by the "top-level" code. So, testing it is legitimate and well-behaved (I also hope, it's what you have in mind).
The code (the main idea is to go from a single but "untestable" recursive function to an equivalent pair of recursively dependent (and thus testable) functions):
def factorial(n):
"""Everyone knows this functions contract:)
Internally designed to use 'factorial_impl' (hence recursion)."""
return factorial_impl(n, factorial_impl)
def factorial_impl(n, fct=factorial):
"""This function's contract is
to return 'n*fct(n-1)' for n > 1, or '1' otherwise.
'fct' must be a function both taking and returning 'int'"""
return n*fct(n - 1) if n > 1 else 1
The test:
import unittest
class TestFactorial(unittest.TestCase):
def test_impl(self):
"""Test the 'factorial_impl' function,
'wiring' it to a specially constructed 'fct'"""
def fct(n):
"""To be 'injected'
as a 'factorial_impl''s 'fct' parameter"""
# Use a simple number, which will 'show' itself
# in the 'factorial_impl' return value.
return 100
# Here we must get '1'.
self.assertEqual(factorial_impl(1, fct), 1)
# Here we must get 'n*100', note the ease of testing:)
self.assertEqual(factorial_impl(2, fct), 2*100)
self.assertEqual(factorial_impl(3, fct), 3*100)
def test(self):
"""Test the 'factorial' function"""
self.assertEqual(factorial(1), 1)
self.assertEqual(factorial(2), 2)
self.assertEqual(factorial(3), 6)
The output:
Finding files...
['...py'] ... done
Importing test modules ... done.
Test the 'factorial' function ... ok
Test the 'factorial_impl' function, ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
The test class below verifies that a simple HttpService gets content from a given URL. Both the implementations shown make the test pass, though one is clearly wrong because it constructs the URL with an incorrect argument.
To avoid this and correctly specify the behaviour I want, I'd like to verify that in the use block of the test case, I construct one (and only one) instance of the URL class, and that the url argument to the constructor is correct. A Groovy enhancement seems like it would let me add the statement
mockURLContext.demand.URL { assertEquals "http://www.foo.com", url }
but what can I do without that Groovy enhancement?
Update: Replaced "mock" with "stub" in the title, as I'm only interested in checking the state not necessarily the detail of the interactions. Groovy has a StubFor mechanism that I haven't used, so I'll leave my code as is, but I think you could just replace MockFor with StubFor throughout.
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
void testGetsContentForURL() {
def content = [text : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { content }
mockURLContext.use {
def httpService = new HttpService()
assertEquals content.text, httpService.getContentFor("http://www.foo.com")
}
}
}
// This is the intended implementation.
class HttpService {
def getContentFor(url) {
new URL(url).content.text
}
}
// This intentionally wrong implementation also passes the test!
class HttpService {
def getContentFor(url) {
new URL("http://www.wrongurl.com").content.text
}
}
What does mocking the URL get you? It makes the test difficult to write. You won't be able to react to feedback the mock objects give you about the design of the API of the URL class, because it's not under your control. And if you don't precisely fake the behaviour of the URL and what it exposes about the HTTP protocol, the test will not be reliable.
You want to test that your "HttpService" object actually loads the data correctly from a given URL, copes with different content type encodings correctly, handles different classes of HTTP status code appropriately, and so forth. When I need to test this kind object -- one that merely wraps some underlying technical infrastructure -- I write a real integration test that verifies that the object really does use the underlying technology correctly.
For HTTP I write a test that creates an HTTP server, plugs a servlet into the server that will return some canned data, passed the URL of the servlet to the object to make it load the data, check that the loaded result is the same as the canned data used to initialise the servlet, and stop the server in the fixture tear-down. I use Jetty or the simple HTTP server that is bundled with JDK 6.
I'd only use mock objects to test the behaviour of objects that talk to the interface(s) of that object I've integration tested.
Putting on my "Programming in the Small" and "Unit test 100%" hat, you could consider this as a single method that does too many things. You could refactor the HttpService to:
class HttpService {
def newURLFrom(urlString) {
new URL(urlString)
}
def getContentText(url) {
url.content.text
}
def getContentFor(urlString) {
getContentText(newURLFrom(urlString))
}
}
This would give you a few more options for testing, as well as split out the factory aspect from the property manipulation. The testing options are bit more mundane then:
class HttpServiceTests extends GroovyTestCase {
def urlString = "http://stackoverflow.com"
def fauxHtml = "<html><body>Hello, world</body></html>";
def fauxURL = [content : [text : fauxHtml]]
void testMakesURLs() {
assertEquals(urlString,
new HTTPService().newURLFrom(urlString).toExternalForm())
}
void testCanDeriveContentText() {
assertEquals(fauxHtml, new HTTPService().getContentText(fauxURL));
}
// Going a bit overboard to test the line combining the two methods
void testGetsContentForURL() {
def service = new HTTPService()
def emc = new ExpandoMetaClass( service.class, false )
emc.newURLFrom = { input -> assertEquals(urlString, input); return fauxURL }
emc.initialize()
service.metaClass = emc
assertEquals(fauxHtml, service.getContentFor(urlString))
}
}
I think that this makes all the assertions that you want, but at the cost of sacrificing test readability in the last case.
I would agree with Nat about this making more sense as an integration test. (You are integrating with Java's URL library on some level.) But assuming that this example simplifies some complex logic, you could use the metaclass to override the instances class effictvely partially mocking the instance.
It's tough to mock out JDK classes that are declared final... Your problem, as you reference through the enhancement, is that there is no way to create a URL other than calling the constructor.
I try to separate the creation of these kinds of objects from the rest of my code; I'd create a factory to separate the creation the URLs. This should be simple enough to not warrant a test. Others take a typical wrapper/decorator approach. Or you may be able to apply the adapter pattern to translate to domain objects that you write.
Here is a similar answer to a surprisingly similar problem: Mocking a URL in Java
I think this demonstrates something that a lot of people learn after doing more testing: the code we write to make things more testable is meant to isolate what we desire to test from what we can safely say is already tested somewhere else. It's a fundamental assumption we have to make in order to do unit testing. It can also provide a decent example of why good unit tests aren't necessarily about 100% code coverage. They have to be economical, too.
Hope this helps.
What exactly are you expecting to have fail? It is not readily apparent what you are trying to test with that code. By Mocking URL.getContent you are telling Groovy to always return the variable content when URL.getContent() is invoked. Are you wishing to make the return value of URL.getContent() conditional based upon the URL string? If that is the case, the following accomplishes that:
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
def connectionUrl
void testGetsContentForURL() {
// put the desired "correct" URL as the key in the next line
def content = ["http://www.foo.com" : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { [text : content[this.connectionUrl]] }
mockURLContext.use {
def httpService = new HttpService()
this.connectionUrl = "http://www.wrongurl.com"
assertEquals content.text, httpService.getContentFor(this.connectionUrl)
}
}
}