Is it OK to mix Assert and Act steps? Is AAA more of a guideline than a rule? Or am I missing something?
Here is my test:
[TestMethod]
public void CancelButtonSelected_DontCancelTwiceThenCancel_DialogCloses()
{
// Arrange
IAddAddressForm form = Substitute.For<IAddAddressForm>();
// Indicate that when Show CancelMessage is called it
// should return cancel twice (saying we want to cancel the cancel)
// then it should return ok
form.ShowCancelMessage().Returns(DialogResult.Cancel,
DialogResult.Cancel, DialogResult.OK);
AddAddressController controller = new AddAddressController(form);
AddressItem item = TestHelper.CreateAddressBob();
// Act
EnterAddressInfo(form, controller, item);
controller.CancelButtonSelected();
Assert.IsTrue(form.DialogResult == DialogResult.None);
controller.CancelButtonSelected();
Assert.IsTrue(form.DialogResult == DialogResult.None);
controller.CancelButtonSelected();
// Assert
Assert.IsTrue(form.DialogResult == DialogResult.Cancel);
}
So I call a method 3 times. After each call, I want to make sure that we did not really cancel the dialog. Then on the third call, the dialog should be canceled.
Is this "legal" use of AAA syntax/styling?
AAA is a guideline to make your unit tests more readable. In the example you provided I would argue you have not achieved that goal.
I think the following tests make the scenario you are testing more readable.
[TestMethod]
public void CancelButtonSelected_ShouldSetDialogResultToNone_WhenFirstCancelButtonIsSelected()
{
// Arrange
IAddAddressForm form = ArrangeFormForCancelButtonSelectedTests();
AddAddressController controller = ArrangeControllerForCancelButtonSelectedTests();
// Act
controller.CancelButtonSelected();
// Assert
Assert.IsTrue(form.DialogResult == DialogResult.None);
}
[TestMethod]
public void CancelButtonSelected_ShouldSetDialogResultToNone_WhenSecondCancelButtonIsSelected()
{
// Arrange
IAddAddressForm form = ArrangeFormForCancelButtonSelectedTests();
AddAddressController controller = ArrangeControllerForCancelButtonSelectedTests();
// Act
controller.CancelButtonSelected();
controller.CancelButtonSelected();
// Assert
Assert.IsTrue(form.DialogResult == DialogResult.None);
}
[TestMethod]
public void CancelButtonSelected_ShouldSetDialogResultToCancel_WhenThirdCancelButtonIsSelected()
{
// Arrange
IAddAddressForm form = ArrangeFormForCancelButtonSelectedTests();
AddAddressController controller = ArrangeControllerForCancelButtonSelectedTests();
// Act
controller.CancelButtonSelected();
controller.CancelButtonSelected();
controller.CancelButtonSelected();
// Assert
Assert.IsTrue(form.DialogResult == DialogResult.Cancel);
}
AAA is just a guideline to make your unit tests more readable. It is perfectly OK to deviate if you have a good reason to do so. You used whitespaces and comments to separate the different phases in code to some extent, which is good. In such cases it may also be helpful to add comments explaining the story you are testing.
Related
Spock has setupSpec on the Spec class level. I would want to have something similar for a single test case level.
This might not be available in Spock, Does someone has a workaround for this.
void "test something"() {
setup:
User user = createUser()
when:
user.setAdress(new Address(zipCode: inputZipCode, city: inputCity))
then:
user.address.city == inputCity
user.address.zipCode == inputZipCode
cleanup:
deleteUser(user)
where:
inputCity | inputZipCode
"a" |"1"
"b" |"2"
}
Creating and deleting user is unnecessarily done after every iteration.
Could it be possible to have something la- setupSpec for a single test instead of class-level?
It is possible to manipulate the test cases to use class-setupSpec/CleanupSpec or even create a new test (with #Stepwise) to achieve this but I am looking for something good solution not a hack.
I think this is very ugly because it involves manual bookkeeping. I do not recommend you to do it like this, but anyway:
package de.scrum_master.stackoverflow.q57721328
import spock.lang.See
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
class OneTimeSetupCleanupParametrisedTest extends Specification {
#Shared User user
#Shared int iteration
User createUser() {
// Set up test fixture only if iteration == 0 (or optionally, if fixture is uninitialised)
user ?: new User()
}
void deleteUser(User userInstance) {
// Clean up counter (and test fixture, if any) only if iteration == total number of iterations
if (++iteration == specificationContext.currentIteration.estimatedNumIterations) {
userInstance.delete()
user = null
iteration = 0
}
}
// #Unroll
void "test something"() {
setup:
// Call initialiser helper for each iteration, relying on the fact that it will only
// create a text fixture if none exists yet
user = createUser()
when:
user.setAdress(new Address(zipCode: inputZipCode, city: inputCity))
then:
user.address.city == inputCity
user.address.zipCode == inputZipCode
cleanup:
// Call clean-up helper for each iteration, relying on the fact that it will only
// clean up the fixture during the last iteration
deleteUser(user)
where:
inputCity | inputZipCode
"a" | "1"
"b" | "2"
}
static class User {
Address address
User() {
println "creating user"
}
void setAdress(Address address) {
this.address = address
}
void delete() {
println "deleting user"
address = null
}
}
static class Address {
String zipCode, city
}
}
Console log:
creating user
deleting user
Update: The Spock manual says about this topic:
Sharing of Objects between Iterations
In order to share an object between iterations, it has to be kept in a #Shared or static field.
NOTE: Only #Shared and static variables can be accessed from within a where: block.
Note that such objects will also be shared with other methods. There is currently no good way to share an object just between iterations of the same method. If you consider this a problem, consider putting each method into a separate spec, all of which can be kept in the same file. This achieves better isolation at the cost of some boilerplate code.
Man, this firebase unit testing is really kicking my butt.
I've gone through the documentation and read through the examples that they provide, and have gotten some of my more basic Firebase functions unit tested, but I keep running into problems where I'm not sure how to verify that the transactionUpdated function passed along to the refs .transaction is correctly updating the current object.
My struggle is probably best illustrated with their child-count sample code and a poor attempt I made at writing a unit test for it.
Let's say my function that I want to unit test does the following (taken straight from that above link):
// count.js
exports.countlikechange = functions.database.ref('/posts/{postid}/likes/{likeid}').onWrite(event => {
const collectionRef = event.data.ref.parent;
const countRef = collectionRef.parent.child('likes_count');
// ANNOTATION: I want to verify the `current` value is incremented
return countRef.transaction(current => {
if (event.data.exists() && !event.data.previous.exists()) {
return (current || 0) + 1;
}
else if (!event.data.exists() && event.data.previous.exists()) {
return (current || 0) - 1;
}
}).then(() => {
console.log('Counter updated.');
});
});
Unit Test Code:
const chai = require('chai');
const chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
const assert = chai.assert;
const sinon = require('sinon');
describe('Cloud Functions', () => {
let myFunctions, functions;
before(() => {
functions = require('firebase-functions');
myFunctions = require('../count.js');
});
describe('countlikechange', () => {
it('should increase /posts/{postid}/likes/likes_count', () => {
const event = {
// DeltaSnapshot(app: firebase.app.App, adminApp: firebase.app.App, data: any, delta: any, path?: string);
data: new functions.database.DeltaSnapshot(null, null, null, true)
}
const startingValue = 11
const expectedValue = 12
// Below code is misunderstood piece. How do I pass along `startingValue` to the callback param of transaction
// in the `countlikechange` function, and spy on the return value to assert that it is equal to `expectedValue`?
// `yield` is almost definitely not the right thing to do, but I'm not quite sure where to go.
// How can I go about "spying" on the result of a stub,
// since the stub replaces the original function?
// I suspect that `sinon.spy()` has something to do with the answer, but when I try to pass along `sinon.spy()` as the yields arg, i get errors and the `spy.firstCall` is always null.
const transactionStub = sinon.stub().yields(startingValue).returns(Promise.resolve(true))
const childStub = sinon.stub().withArgs('likes_count').returns({
transaction: transactionStub
})
const refStub = sinon.stub().returns({ parent: { child: childStub }})
Object.defineProperty(event.data, 'ref', { get: refStub })
assert.eventually.equals(myFunctions.countlikechange(event), true)
})
})
})
I annotated the source code above with my question, but I'll reiterate it here.
How can I verify that the transactionUpdate callback, passed to the transaction stub, will take my startingValue and mutate it to expectedValue and then allow me to observe that change and assert that it happened.
This is probably a very simple problem with an obvious solution, but I'm very new to testing JS code where everything has to be stubbed, so it's a bit of a learning curve... Any help is appreciated.
I agree that unit testing in the Firebase ecosystem isn't as easy as we'd like it to be. The team is aware of it, and we're working to make things better! Fortunately, there are some good ways forward for you right now!
I suggest taking a look at this Cloud Functions demo that we've just published. In that example we use TypeScript, but this'll all work in JavaScript too.
In the src directory you'll notice we've split out the logic into three files: index.ts has the entry-logic, saythat.ts has our main business-logic, and db.ts is a thin abstraction layer around the Firebase Realtime Database. We unit-test only saythat.ts; we've intentionally kept index.ts and db.ts really simple.
In the spec directory we have the unit tests; take a look at index.spec.ts. The trick that you're looking for: we use mock-require to mock out the entire src/db.ts file and replace it with spec/fake-db.ts. Instead of writing to the real database, we now store our performed operations in-memory, where our unit test can check that they look correct. A concrete example is our score field, which is updated in a transaction. By mocking the database, our unit test to check that that's done correctly is a single line of code.
I hope that helps you do your testing!
apologized to post this question here but i am in problem suddenly because i need to write unit test code for action where i am not good.
i am bit familiar with asp.net mvc. before i never write unit test code for action rather i manually test the action. now i want to know the art of writing unit test code for my action. so i read couple of article on unit test but notice all article share very basic idea about to write unit test code for action method in mvc controller but i am not being able to write unit test code for my action. so here i am pasting my one sample controller and their actions. so anyone please share knowledge how to write unit test code for my action methods below. if possible discuss with code sample or good hint which enable to write unit test code in VS2013 and MVC version 5.
here is my code
public class StudentController : Controller
{
private StudentRepository _Studentdata;
private StateRepository _Statedata;
private CityRepository _Citydata;
public StudentController()
{
_Studentdata = new StudentRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentDBContext"].ConnectionString);
_Statedata = new StateRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentDBContext"].ConnectionString);
_Citydata = new CityRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentDBContext"].ConnectionString);
//_Studentdata = new StudentRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentSQLDBContext"].ConnectionString);
//_Statedata = new StateRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentSQLDBContext"].ConnectionString);
//_Citydata = new CityRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentSQLDBContext"].ConnectionString);
}
// GET: Stuent
public ActionResult List(StudentListViewModel oSVm)
{
if (Request.IsAjaxRequest())
System.Threading.Thread.Sleep(1000); // just simulate delay of one second
StudentListViewModel SVm = new StudentListViewModel();
SVm.SetUpParams(oSVm);
SVm.Students = _Studentdata.GetStudents(oSVm.page, oSVm.PageSize, oSVm.sort, oSVm.sortdir).ToList();
SVm.States = _Statedata.GetAll().ToList();
SVm.Cities = _Citydata.GetAll().ToList();
SVm.RowCount = _Studentdata.DataCounter;
return View("ListStudents",SVm);
}
[HttpPost]
public ActionResult UpdateStudents(StudentListViewModel oSVm, string Action)
{
if (Request.IsAjaxRequest())
System.Threading.Thread.Sleep(1000); // just simulate delay of one second
StudentListViewModel SVm = new StudentListViewModel();
SVm.SetUpParams(oSVm);
if (Action == "UPDATE")
{
SVm.Students = _Studentdata.SaveXML(new List<Student>(oSVm.Students).ToXml("Students"),
oSVm.page, oSVm.PageSize, oSVm.sort, oSVm.sortdir).ToList();
}
else if (Action == "DELETE")
{
SVm.Students = _Studentdata.Delete(oSVm.Students[0].ID,
oSVm.page, oSVm.PageSize, oSVm.sort, oSVm.sortdir).ToList();
}
SVm.States = _Statedata.GetAll().ToList();
SVm.Cities = _Citydata.GetAll().ToList();
SVm.RowCount = _Studentdata.DataCounter;
return PartialView("_StudentGrid", SVm);
}
[HttpPost]
public ActionResult RefreshStudents(StudentListViewModel oSVm)
{
if (Request.IsAjaxRequest())
System.Threading.Thread.Sleep(1000); // just simulate delay of one second
StudentListViewModel SVm = new StudentListViewModel();
SVm.SetUpParams(oSVm);
SVm.Students = _Studentdata.GetStudents(oSVm.page, oSVm.PageSize, oSVm.sort, oSVm.sortdir).ToList();
SVm.States = _Statedata.GetAll().ToList();
SVm.Cities = _Citydata.GetAll().ToList();
SVm.RowCount = _Studentdata.DataCounter;
return PartialView("_StudentGrid", SVm);
}
[HttpGet]
public JsonResult GetCityName(int StateID)
{
if (Request.IsAjaxRequest())
System.Threading.Thread.Sleep(1000); // just simulate delay of one second
return Json(new {CityList =_Citydata.GetCityByStateId(StateID)} , JsonRequestBehavior.AllowGet);
}
}
Thanks
I've got an action in my controller:
def dirtyMarker() {
render(template: '/layouts/modals/marker/dirtyMarker')
}
and Id like to unit test it. Ive been trying lots of possibilities. This may seem simple, but nothing seems to work (Grails 2.2.3). I know that here, testing might not be important but Ive got lots of other methods that returns a rendered template and I dont know how to implement this test..
seems to me that this should work:
void dirtyMarker() {
controller.metaClass.render = { Map params ->
assert params.template == '/layouts/modals/marker/dirtyMarker'
return 'a'
}
def result = controller.dirtyMarker()
assert result == 'a'
}
You can also mock the template:
void testDirtyMarker() {
views['/layouts/modals/marker/_dirtyMarker.gsp'] = 'mock contents'
controller.dirtyMarker()
assert response.text == 'mock contents'
}
See Testing Template Rendering for details
I'm fairly new to unit testing and we are actually attempting to use it on a project. There is a property like this.
public TimeSpan CountDown
{
get
{
return _countDown;
}
set
{
long fraction = value.Ticks % 10000000;
value -= TimeSpan.FromTicks(fraction);
if(fraction > 5000000)
value += TimeSpan.FromSeconds(1);
if(_countDown != value)
{
_countDown = value;
NotifyChanged("CountDown");
}
}
}
My test looks like this.
[TestMethod]
public void CountDownTest_GetSet_PropChangedShouldFire()
{
ManualRafflePresenter target = new ManualRafflePresenter();
bool fired = false;
string name = null;
target.PropertyChanged += new PropertyChangedEventHandler((o, a) =>
{
fired = true;
name = a.PropertyName;
});
TimeSpan expected = new TimeSpan(0, 1, 25);
TimeSpan actual;
target.CountDown = expected;
actual = target.CountDown;
Assert.AreEqual(expected, actual);
Assert.IsTrue(fired);
Assert.AreEqual("CountDown", name);
}
The question is how do I test the code in the setter? Do I break it out into a method? If I do it would probably be private since no one else needs to use this. But they say not to test private methods. Do make a class if this is the only case? would two uses of this code make a class worthwhile? What is wrong with this code from a design standpoint. What is correct?
The way you've got is fine (call the setter and then check the get returns the expected value).
Make sure you choose a selection of test values that exercise all the paths in that setter. A single set/get test isn't sufficient coverage.