I'm pretty new in Unit testing.
We made a test
It starts with a certain content of a database
then there can 2 things happen.
Amsterdam is overwritten with Amsterdam
or
Amsterdam stays Amsterdam.... (nothing happens)
What is the best way to verify what of both happened?
Normally, you would test each case, and you can use a Mock Object to remove the dependency on the database.
In this case, you would structure a test that recognizes that nothing changed in the DB record. The Mock object returns a state from the database indicating that nothing has changed. Your test would then check that the code that executes next, reported this condition, and therefore passes the test.
A second test would then be done where the Mock Object returns the state from the database where the item was changed, so then the code that should be executed does what it should, and passes your test.
Repeat the above tests for failing conditions, and you have your code covered.
class YourDBClass {
private $DBRef;
// Constructor Injection, pass the Database object here
public function __construct($DatabaseObject = NULL)
{
if(! is_null($DatabaseObject) )
{
if($DatabaseObject instanceof YourDBAccessClass)
{
$this->SetDBClass($DatabaseObject);
}
}
}
function SetDBClass(YourDBAccessClass $DatabaseObject)
{
$this->DBRef = $DatabaseObject
}
function GetResult($request) {
$DBR = $this->DBRef;
$result = $DBRef->DoSomething($request);
if ($result->success == false)
$result->error = $this->GetErrorCode($result->errorCode);
}
function GetErrorCode($errorCode) {
// do stuff
}
}
Test:
class YourDBClassTest extends PHPUnit_Framework_TestCase
{
// Simple test for GetErrorCode to work Properly
public function testGetErrorCode()
{
$TestClass = new YourDBClass();
$this->assertEquals('One', $TestClass->GetErrorCode(1)); // Assumes GetErrorCode returns a string
$this->assertEquals('Two', $TestClass->GetErrorCode(2));
}
// Could also use dataProvider to send different returnValues, and then check with Asserts.
public function testGetResultsNoChange()
{
// Create a mock for the YourDBAccessClass,
// only mock the GetResult() method.
$MockService = $this->getMock('YourDBAccessClass', array('GetResult'));
// Set up the expectation for the GetResult() method
$MockService->expects($this->any())
->method('GetResult')
->will($this->returnValue("NoChange"));
// Create Test Object - Pass our Mock as the service
$TestClass = new YourDBClass($MockService);
// Or
// $TestClass = new YourDBClass();
// $TestClass->SetDBClass($MockService);
// Test GetResults
$QueryString = 'Some String since we did not specify it to the Mock'; // Could be checked with the Mock functions
$this->assertEquals('NoChange', $TestClass->GetResults($QueryString));
}
// Could also use dataProvider to send different returnValues, and then check with Asserts.
public function testGetResultsChanged()
{
// Create a mock for the YourDBAccessClass,
// only mock the GetResult() method.
$MockService = $this->getMock('YourDBAccessClass', array('GetResult'));
// Set up the expectation for the GetResult() method
$MockService->expects($this->any())
->method('GetResult')
->will($this->returnValue("Amsterdam Changed"));
// Create Test Object - Pass our Mock as the service
$TestClass = new YourDBClass($MockService);
// Or
// $TestClass = new YourDBClass();
// $TestClass->SetDBClass($MockService);
// Test GetResults
$QueryString = 'Some String since we did not specify it to the Mock'; // Could be checked with the Mock functions
$this->assertEquals('Amsterdam Changed', $TestClass->GetResults($QueryString));
}
}
Steven, I discussed with my colleauges, They understand what you do.
but this is what we actually needed:
mysql UPDATE statement - overhead for same values?
I hope you follow. Nevertheless, thank you so much!
Related
I've recently taken upon myself to add setter and getter methods to my class.
Since doing this, many parts of my code got broken and I'm unable to access getter methods.
Take the example below:
private loadInputs() : Input[] {
var inputs = <Input[]>this.get('inputs');
inputs.sort((a,b) => a.QuoteRef().localeCompare(b.QuoteRef()))
return( inputs || [] );
}
My input class has 2 variables,
_Project: string
_line: string
Which I access using a method QuoteRef()
public QuoteRef(): string {
return this._Project.concat('-' + this._Line.toString().padStart(3,'0'));
}
Whenever I try to access a method or a getter from my class on an item that is casted as an Input, I can see the variables (though not access them as they are private), but the prototype section doesn't contain any of the methods.
This triggers the following error in the website console:
TypeError: a.QuoteRef is not a function
What am I doing wrong?
Update
I got it to work by updating the code as follows:
inputs.sort((a,b) => {
let first = new Input(a);
let second = new Input(b);
return first.QuoteRef().localeCompare(second.QuoteRef());
});
Without seeing your complete class I can only guess, but I think that a and b in your sort are not of the type you expect. I can't see what this.get('inputs') does, but I suspect it is not returning an array with Input class objects. Hence the function cannot be found (is not a function). You could try:
inputs.sort((a,b) => {
console.log(typeof a);
console.log(typeof b);
a.QuoteRef().localeCompare(b.QuoteRef());
})
and check what the type is. Then check what your this.get actually returns.
Edit: forgot to mention that your IDE probably does not warn you because you cast the output of this.get to <Input[]>.
I am trying to understand the value of this at different points in a script. Questions similar to mine have been answered in this forum but those answers are considerably above my current learning level.
In my code experiments, I am using console.logs to return the this value. The value returned is always as expected, but the format of the returned value is inconsistent, which leads me to wonder why.
This code returns the expected Window object for the first 3 log commands to be executed but returns only the object literal for the 4th command, executed from the object's method.
var myName = {
name: "James",
sayName: function() {
console.log(this, 4);
console.log(this.name)
}
}
console.log(this, 1);
function myFunction() {
console.log(this, 2);
function nestFunction() {
console.log(this, 3);
myName.sayName();
}
nestFunction();
}
myFunction();
I have 3 questions: Why doesn't console.log return the name of the object? Is there a way to make it do so? Is there a simple way to do that other than console.log? Any help would be appreciated.
Ok I was going through your code to see what you specifically mean
here is the short explanation as to why THIS is different in some of the places
This keyword refers to the object it belongs to. Generally you used it to refer to the global window object .That's what is reflecting in your console log 1,2,3 .
Calling this in static javaScript object will return the javaScript object ,not the window object that is what is reflecting in the console.log(this,4).
So it gives you a way to call elements inside a static object .
Another way to understand this keyword is to look at constructors .The best example of the keyword
this
is inside a constructor function
var myObj = function(){
function myObj(ref)
{
this.name = "";
this.Item = "";
this.ref = ref;
this.speak();
}
myObj.prototype.speak =function()
{
this.name = 'James';
this.item = 'cheese';
console.log(this.ref)
//and the constuctor object
console.log(this)
}
return myObj;
}();
var e = new myObj('a Refrence string');
This should give you a basic understanding of how this works
here is more info to get you started Wschools.com
I currently have 2 pages, page1.php and page2.php, each of the pages uses a controller that completes its own functions etc.
However there are tabs within the pages that are exactly the same that gets a promise from a factory within the module. The lists are exactly the same except for querying on different IDs. For example both controllers have this:
pageListFactory.getData().then(function (result) {
$scope.BasicItems = result; $scope.basicItemsList = [];
angular.forEach($scope.BasicItems, function (BasicItem) {
angular.forEach(BasicItem['SomeInnerArray'], function (BasicSomeInnerItem) {
if (BasicSomeInnerItem == VARIABLE_THAT_CHANGES) {
$scope.basicItemsList.push({
ID: BasicItem.ID, Title: BasicItem.Title
});
}
});
});
});
So this code is used, and the VARIABLE_THAT_CHANGES is just what changes each time. However as I said it is used on multiple pages, is there a way to create just one function call and then each page just can call a specific bit and send the variable with it?
I tried using $rootScope but of course this just clogs and slows, and I'm not exactly happy on constantly using $rootScope to pass the $scope.basicItemsList around as the list could get quite big.
So is there any way to reuse this code without just copying and pasting it into each controller?
Sure you can re-use it...
Convert the factory to a service, its basically a name change, create a local variable to store the data, update the data on first call, and then grab the data if it exists on the second call.
.service('myService', ... stuff ... { // I suggest using a service, as I don't know if a factory would act as a singleton
var myData = null;
return {
getData: function(){
if(myData != null)
return myData; // returns data
else {
return $http()... // ajax call returns promise
}
},
setData: function(dataToSet){
myData = dataToSet;
}
}
Then your controllers:
//controller 1
var promiseOrData = pageListFactory.getData();
if(promiseOrData instanceOf Array){ // or whatever data you expect
$scope.BasicItems = promiseOrData;
....
}
else { // should be a promise
promiseOrData.then(function (result) {
pageListFactory.setData(result); // set the data once you get it.
$scope.BasicItems = result; $scope.basicItemsList = [];
....
}
}
In controller 2 you only need to get the data as the returned data will be an array, not a promise
On top of all this, write a directive which will process the data when you pass it along, then you can pass the variableThatChanges and have the directive take care of it.
Use services and write the function in that service and pass the variable VARIABLE_THAT_CHANGES into it. By this you can reuse the code.
I have an NgComponent that is supposed to load data from another file based on a parameter in the tag. Here is an example tag:
<line-graph width="800" height="250" src="table.csv" />
If I attempt to load data based on the src variable in the constructor, it is null. I know that the value is being set, just at a later time. Is there a way to call the load function when the element is full initialized and the variables have been loaded from that DOM?
implement NgAttachAware and run your code in attach().
I read about a bug that even this is not working with some directives recently.
In this case try to run the code inside attach with new Future(() { your code here });
To make code execute every time the value is changed you can make src a setter and the code in the setter gets executed every time the value is changed.
String _src;
#NgTwoWay('src')
String get src => _src;
set src(String val) {
_src = value;
// your additional code goes here
}
You can accomplish this by using the $watch function. The $watch function will be renamed to watch in the next version. Here is an example implementation:
class Component {
#NgAttr("src")
String src;
Scope scope;
Component(this.scope){
scope.$watch(() => src, (value, previousValue){
if (value == null) return;
//load and draw data
})
}
}
In the next version it will look something like this:
class Component {
#NgAttr("src")
String src;
Scope scope;
Component(this.scope){
scope.watch(src, (value, previousValue){
if (value == null) return;
//load and draw data
})
}
}
I have a method
class Garage{
public Noise myMethod(){
Car mycar = getCarService().getCar("ford");
Noise brum = mycar.drive();
return brum;
}
...
}
I want to mock both the service and the car, so I have created a mock like this
MyCarService carMock = createMock(Car.class)
MyCarService mockServce = createMock(MyCarService.class)
expect(mockService.getCarService().andReturn(carMock));
expect(carMock.drive().andReturn("brummmm"));
replayAll();
Garage garage = new Garage();
garage.setCarService(mockService);
Noise n = g.myMethod();
However when I run the code mycar is always returned from the mockservice as null. Can you do this type of thing with easyMock?
You should not include this line: garage.setCarService(mockService);.
All you need is your expectation of mockService.getCarService() being called, which you have done.
So, when you run your test by invoking g.myNewMethod, when myNewMethod hits the getCarService() method, it will return your mockService.
You are however missing an expectation for the getCar method being called. You need:
expect(mockServce.getCar("ford")).andReturn(carMock);