Home | About Us | Stelligent  

TestEarly Weblog

Business Perspectives

/Glover and Business Perspectives and Agile21 Apr 2008 10:14 am

Jim York, a long time Stelligent friend, a Certified Scrum Trainer and lean and agile coach, is conducting a Certified ScrumMaster class May 5-6 in Vienna, VA.

Learn the essentials of working as ScrumMasters, Product Owners, and Scrum team members in this highly-interactive 2-day class. Jim creates an energized learning environment where participants engage in discussion, hands-on simulations, and role play to explore the nuances of Scrum in action. More than an intellectual exercise, Jim challenges attendees to connect Scrum practices to their underlying guiding principles. This class provides what you can’t get from a book — guided experiential learning in realistic scenarios.

Sign up today as space is limited!

Developer Testing and /Glover and Business Perspectives and Agile01 Apr 2008 08:15 pm

The software development process is a big black box for basically everyone on the planet earth, except for a few, proud individuals who speak geek and wear silly tee-shirts. To everyone else who doesn’t read code or wear silly tee-shirts but work with people who do, the last bit of sanity they have is during the time they get to tell development what they want. After that, stakeholders are left praying that at the end of the developmental process, they get something out of it that works. More often than not, if that developmental process takes a long time, stakeholders don’t get want they want.

i am not groovy
Along came iterative processes and customer involvement and things got better. A little. Stuff still broke. And developers still had horrible manners and wore silly tee-shirts. A few of them also appeared not to have learned basic hygiene.

Then came test driven development. Developers’ manners were the same and they still wore silly tee-shirts, but at least the code wasn’t as horrible. Hygienic concerns remained.

Iterative processes became more popular and the stakeholder wanted more. The stakeholder wanted visibility into that black box that those silly tee-shirt wearing developers called the “dev cycle” or the “software construction phrase” but what the normal people called “sit tight and pray a lot” time or “oh gosh, what’s this gonna cost this time?”. After all, they were paying for it and the tee-shirts those developers wore didn’t make any sense (hygienic concerns not withstanding).

Along came the gurus shouting “traceability!” which makes total sense since stakeholders are paying the bill. Emboldened, stakeholders declared:

“When a user selects 3 items, then they should receive a 10% discount.”

Heads nodded. The look of approval was unmistakable. Business was accelerating forward and everyone was happy.

Soon, stakeholders were summoned. The silly tee-shirt wearing developers proudly showed the stakeholders a test case proving the requirement was met and even tested.

assert-equals

The stakehoders looked puzzled. Confused even. And they weren’t trying to read those silly tee-shirts or ponder hygienic skills. Development put their finest heads together and clarified the situation with some documentation:

easyb is easy baby

The stakeholders did their best to understand what they were looking at. In fact, the code even tried to convey more meaning. Yet, no matter how hard they tried, the stakeholders couldn’t speak geek. They couldn’t read the code. They couldn’t laugh at the tee-shirts. They couldn’t not brush their teeth.

Then one of the stakeholders (who used to wear silly tee-shirts) got an interesting idea– why not leverage the same language for both defining the requirements and validating them? In fact, by leveraging BDD constructs and paying attention to what was originally asked for, things can become quite easy.

This is what was originally asked for:

“When a user selects 3 items, then they should receive a 10% discount.”

The key word being should– in fact, the mechanism by which the requirement was requested sounded an awful lot like a story, which could be written like so:

more asserts

Then working with a few developers (who showered that morning), the stakeholder convinced them to author the story using a BDD framework (like easyb), which yielded a file containing the requirements like so:

more asserts

After the code was implemented, the stakeholder was pleased. Other stakeholders were summoned. Other developers were also summoned. Soon heads nodded. Approval was in the air. Business had been accelerated and all involved parties understood each other, for indeed, stakeholders could read what development had finally produced:

more asserts

Stakeholders rejoiced! Developmental jollification ensued. Speaking geek was no longer needed. Things were written in plain English. Those silly tee-shirts still didn’t make sense, but it didn’t matter anymore– stakeholders got what they wanted. They got validation. They got assurance that indeed their requirements had coverage. They didn’t get some of the developers to shower, but they weren’t asking for miracles, just progress. The “sit tight and pray a lot” time became a collaborative effort. BDD had saved the day.

/Glover and Business Perspectives27 Jan 2008 08:36 pm

I had the pleasure of linking up with Rich Sharpe of Enerjy Software at CodeMash a fews ago where he asked me this direct question:

Is programming an art or a science?

Yeah, tough question, eh? Certainly made me squirm! So what do you think?

Developer Testing and /Glover and Business Perspectives22 Jan 2008 02:03 pm

Test Driven Development, or TDD has quite a few different connotations; in fact, at our recent TDD horror stories event, the definition of TDD itself was split down the middle. Half of the attendees defined TDD as writing a test before writing any code and the other half defined it as writing tests for anything that could break (thus, not necessarily writing a test first).

Of course, TDD stresses tests and by actually writing them, TDD enables a more robust design– so much so that often TDD is thought of as Test Driven Design. Accordingly, TDD facilitates a more maintainable design through the notion of tests. These tests force you to think about the behavior of the code and how to ensure it works as intended. More often than not, code bases influenced by TDD are relatively un-complex and arguably quite simple.

Code that is un-complex and simple is easier to change than code that exhibits opposite traits like complexity and brittleness. What’s more, because code written with TDD in mind is backed by tests, any changes that break the code are quickly spotted. In essence, TDD code is easier to change and easier to fix.

But TDD isn’t about easier changes either– at least not directly. No, TDD is all about speed. When teams execute consistently with TDD in mind, features are produced faster. Faster features means shorter time to market. Shorter time to market means greater change of obtaining more customers. Best of all, that speed to market is backed by a safety net of tests that enable rapid change in the same amount of time (if not quicker).

TDD is all about speed. Fixing defects that could have been spotted during development is a waste of time and money. Companies that are developing software without early testing will undoubtedly be stuck with a code base that can’t change easily– and they’ll be beaten by a company who is more nimble and quick– because they build solid code from the start with TDD.

/Duvall and Business Perspectives08 Nov 2007 03:50 am

We received over 80,000 unique hits to my blog post, “Fire your ‘best’ people, reward the ‘lazy’ ones”. Based on comments here and postings on other sites, it’s fair to say that many of you seem to agree that if you have too many people on a project that focus exclusively on troubleshooting, you’ve got a problem. I figured this post deserved further explanation…

Milton

I wrote this based on my experiences in working on dozens of projects as either a developer, tester, PM, architect or consultant. Some of the behavior that teams are rewarding will not lead to getting better software out the door faster. There’s no way you can prevent every problem from occurring on a project. However, when problems do occur, it’s important to ask two questions:

Why did this happen?”

-and -

“What are we going to do to prevent it from happening again?”

That’s it. People need to troubleshoot issues, but they must also be asking these questions after fixing the problem. In the post, I pit the troubleshooter against the troublepreventer, but I go on to say that, without question, you need troubleshooters on your project. I am poking at the people that focus so much on troubleshooting that they forget to look to prevent the problem from occurring in the first place. The time you invest in fixing or preventing a problem should be based on risk. It’s probably not worth investing several days on preventing a problem from occurring if the likelihood of its occurrence is low and the impact of the realizing the risk is minimal. However, it may be worth your time if the likelihood is low/medium and the impact is high/severe (e.g. application will not work). Obviously, if it’s already happened, the likelihood is rather high, don’t you think?

Even today, there are many that firmly believe that if a team works to improve/introduce software quality, it will delay the schedule. The antithesis is a false economy . In my experience, effectively employing practices/techniques such as developer testing, creating a fully automated build, continuous integration (CI), and automated deployment speed up quality and delivery with teams. Of course, I used a trick (some may say ‘clever’) word in the previous sentence…”effectively”. For instance, if you try to do CI without a fully automated build, you will have problems. Or, try to write developer tests that rely on specific values in the database that aren’t aren’t updated/integrated into scripts, you’ll have problems. There’s no silver bullet here.

People will ask, so “If I do TDD, CI and automated builds, will this improve my speed and quality of delivery?” I must, in all good conscience, give you the consultant’s answer: “It depends!” If you’re incorrectly implementing these practices, it doesn’t matter what you call it, they’re not going to magically solve problems just because you gave it a name. Unfortunately, the practices themselves can be misappropriated as the culprit of the schedule delay or quality problems (e.g. I always get a chuckle out of the: “We stopped using CI because our builds kept failing”).

Fail fast is a good mantra to follow. Learn from your mistakes and improve. Reacting to the latest emergency is necessary and inevitable. However, teams should seek to always learn and improve to lessen these occurrences in the future. People may say “Well, that’s just obvious!” Then, I will leave you with one of my favorite blog posts from Kathy Sierra. There’s a difference between saying and doing .

/Cox and Business Perspectives and Agile19 Oct 2007 11:57 am

I had the pleasure of attending the Agile Project Leadership Network (APLN) Fall Leadership Summit in Richmond, VA yesterday. This was a great event and I would encourage anyone to attend future APLN sponsored events. I collected some quotes I overheard yesterday and have provided some explanation as to why I found them interesting. Some of the longer quotes are paraphrases; please forgive any inaccuracies.

10. “It seems like all of this Agile stuff is just common business sense.”
This late question during the Lunch Panel was from one of the few attendees who has not yet experienced effective Agile practices. Of course, Agile is based in the common-sense business practices of increased communication, eliminating bureaucratic barriers, empowering the individual and collaborative management. These may be common sense, but I am not sure how common they are in practice.

9. “You should take your customer outside and shoot them.”
This laughable comment was suggested during a Think Tank session. The customer in question was demanding an Agile approach and refusing to prioritize a thousand-item requirements document. The speaker of this advice was joking, I think.

8. “Agile will not create competence.”
Steve Greene, Director of Tools and Processes at salesforce.com, emphasized the strength of his team as an indicator of Agile success and the panel agreed that the transparency inherent in an Agile approach will highlight those who are struggling to perform effectively.

7. “The embedded social engineering practices of Scrum give it a significant advantage.”
In a personal discussion with Robin Dymond, a managing partner at Lean and Agile consultancy innovel, LLC, he highlighted the important concept that Planning Poker, Daily Scrums and Continuous Integration are all examples of social engineering constructs designed to improve communication (and eliminate a huge barrier to positive project velocity.)

6. “I’m not sure if we are reaching your Zen state of Agile with this answer.”
Responding to a question regarding the “next higher state” of Agile teams, this Panel answer from Roy Maines of Wachovia received a few laughs.

5. “Our biggest challenge is translating the value of Agile into a pricing structure that resonates with our customers.”
I heard this comment stated several different ways by development companies/teams with external customers. The challenge being that the customers want to know “what is this thing (the final version) going to cost and how long will it take to build?” The answer was ultimately some version of “let us deliver something valuable in our first sprint and build on it from there.” Several people indicated frustration that this answer was not good enough for their customers.

4. “Now that our projects are Agile, we are discovering our infrastructure is struggling to keep up.”
Of course, this one was near and dear to my heart, as Stelligent specializes in helping companies overcome this challenge. Several leaders noted that their waterfall-influenced development infrastructure and software developers unfamiliarity with accelerated delivery principles was a barrier to fully realizing the advantages of their Agile transformation.

3. The entire presentation from Israel Gat.
Unfortunately, I cannot provide a simple “nugget” from Israel’s presentation that moved from the bitch-goddess Success through empirical analysis of the actual impact of Agile within BMC Software. The real-world, large-scale analysis of Agile’s overwhelming success within BMC was fascinating.

2. “Despite all advice from consultants, we went all-Agile, all-at-once.”
Another quote from Salesforce’s Steve Greene in a very interesting talk about how inter-related project dependencies prevented them from the tried-and-true approach of starting Agile with a small pilot and allowing it to build through an organization over time. Salesforce turned Agile all on, all at once, and has never looked back…an impressive story of corporate culture, resolve and confidence.

1. “At a minimum, I want to be able to react to market conditions. My desire is to shape market conditions. My goal for IT is to not get in the way.”
The keynote speaker, Niel Nickolaisen, CIO and Director of Strategic Planning, Headwaters, Inc. led off with this important business perspective on why companies have interest in being Agile. The ability to link Agile practices will business goals is a key skill for anyone looking to transform an organization. I felt this comment best reflected the sentiment of the panelist, speakers and attendees that Agile is not the end, it is the means; business value is the true goal.

So, what do you think? Did you attend the summit? What did I miss? Regardless, what do you think of some of these ideas and thoughts? Are you experiencing similar challenges and successes?

/Glover and Business Perspectives and Agile07 Sep 2007 03:11 pm

When you see (or hear) the phrase “software defect” what does that mean to you? Other than the obvious fact that defects are bad, what are they? If you are a fan of wikipedia, then maybe you liken a defect to:

an error, flaw, mistake, failure, or fault in a computer program that prevents it from behaving as intended

I certainly agree with this definition; however, the latter part of it (”prevents it from behaving”) tends to focus on a running application. Don’t get me wrong, defects (as we’re used to defining them) usually manifest themselves when an application is run (i.e. the nefarious Blue Screen of Death); nevertheless, if you subscribe to the notion that code should be, in essence, mistake proof through arduous early testing, then I have found that by expanding the definition of what a defect is has the benefit of improving a software development process by highlighting how one’s actions from day one can have long terms implications.

For instance, if your definition of a defect is limited to application behavior (say, in user terms), you may end up delaying your own ability to actually find them. The time delta between when code is cut and when someone can exercise some sort of acceptance test is directly related to an increase in actual costs (as everyone already knows). This is why, of course, Agile methodologies espouse short iterations as opposed to big bang waterfall-like cycles.

Alternatively, if you broaden your definition of a defect, then you can, more often than not, find them sooner. Assuming your team is actually writing developer tests, then a defect could be that a test failed (note that 9 times out of 10, a developer test is executed against a portion of a running system). Ideally, if tests exist and you’ve got an automated build system, then you can run those tests often (like every time your SCM system changes via Continuous Integration). Already, in this scenario, you can find defects early.

What if you take it a step further– say, if a failing developer test is considered a defect, then perhaps another form of a defect could be the lack of a developer test? If you define “legacy code” as code that doesn’t have a unit test and you’ve committed to stop writing legacy code, then by definition, code that is modified or new and doesn’t have a test is therefore legacy code (which is bad); hence, the addition of legacy code into an SCM should be a defect!

But wait! Developer tests (i.e. unit tests) require that people actually write them (in some cases they can be generated). And as I noted earlier, tests are usually executed against a running system. What if you further expanded your definition of a defect to include variations in code metrics, such as complexity? For example, if you are able to measure complexity (such as cyclomatic complexity) and you tend to eschew it, then if complexity increases, you can surely consider that a defect, can’t you?

You can even combine various measurable aspects of developmental activities to further exploit finer grained defects. For example, if you have developer tests, then you can surely obtain code coverage numbers. Once you’ve obtained coverage values, if they drop, you can infer a few things:

  • New code was added that doesn’t have any tests for it (legacy code == defect)
  • Someone deleted some tests

Either way, code coverage dropped, so why not consider that a defect?

What’s more, why not combine measurements further– if code coverage drops for a particular section of code AND the complexity of that code increased, bingo! Defect. Of course, the combinatorics go on, but hopefully, the point is evident: if you broaden what a defect is to you, you can then do things to find them early.

Your definition will be different based upon business needs as well, but rest assured that if you want to produce reliable code quickly, you’ve got to find defects as early as possible and to do that you’ve got to expand your definition of a defect.

/Duvall and Business Perspectives17 Aug 2007 10:47 am

Fire your “best” people…reward the “lazy” ones

In my experience, what most people consider to be their “best” people are often the root of most problems. It’s the difference between troubleshooters and troublepreventers.

Let me explain…

Bill Lumbergh

Bill is a troubleshooter (only). Many consider Bill to be the best employee in the company because he solves almost any problem that comes into the door. However, unbeknownst to many (especially management), Bill is the one causing most of the problems. Bill knows the purpose of every hard-coded lookup value and is the fastest to manually deploy the application to WebLogic using its web console. For instance, he knows that “14″ means a “transaction that is waiting for approval by second-line management”. However, instead of creating a human-readable constant, Bill hard codes the number “14″ in the source code. Therefore, Bill is the only one that can easily maintain these methods. In my personal experience, someone like Bill doesn’t do this for nefarious reasons, he’s just not thinking about how the next developer may need to maintain it. For every time a method is written, it’s read (and maintained) ten times (10:1). Therefore, people like Bill need to be writing source code for other humans, not the computer.

Let’s have a look at Peter…

Peter

Peter is a “lazy” developer (a troublepreventer). Because Peter is “lazy”, he hates doing the same thing twice, so he generalizes common functionality into a delegating class, creates interfaces for implementing classes to adhere to, or he writes build scripts that compile, integrate the database, runs tests and inspections, and deploys the software the same way every time. Peter finds it mind-numbing to repeat himself. Again, Peter is lazy so he doesn’t mind spending two hours automating something that normally takes 10 minutes to run manually. Why? Because, he very quickly reaps the benefits of this extra effort since every time the process is run he gets those 10 minutes back and even more importantly, he eliminates the possibility of human error (which, again, saves time and money).

The (”lazy”) troublepreventer thinks ahead. He extracts variable information into common properties files, seeks to reduce complex code, and automates repetitive, error-prone activities such as the build and deployment processes. He also ensures that others can very easily repeat what he has done. Anyone that has worked with me for even a day knows that I often sound like a broken record when I say “Is it in Subversion?” or “Have you updated the Wiki?” To me, if the knowledge is locked in your head, you are a less valuable, not more valuable, resource. Troublepreventers put their knowledge in the system, not just their heads, so that it runs the same way every time.

People like troubleshooters because they can solve a problem when a project is under pressure such as getting that emergency fix out the door immediately. Without question, you need troubleshooters on your project. However, many times the (exclusive) troubleshooters are the ones that cause the problem in the first place, be it a hard-coded value, duplication of code or a large complex method only they can understand.

Before you start thinking that I’m trying to gather together a group of slackers, I’m suggesting the complete opposite of this. I just want people to think about the total time involved, not just fixing the symptom. There are people that are both troublepreventers and troubleshooters. These are the people you want to keep and reward. However, on a given team, I’d opt for more troublepreventers than troubleshooters as they save everyone time, money and headaches.

Build Management and /Cox and Business Perspectives07 Aug 2007 11:23 am

In his excellent book, Customer Centered Selling, Robert Jolles relays a poem about consequences:

FOR WANT OF A NAIL

For want of a nail, a shoe was lost
For want of a shoe, a horse was lost
For want of a horse, a rider was lost
For want of a rider, a message was lost
For want of a message, a battle was lost
For want of a battle, a war was lost
And all for the want of a nail…

Ben Franklin

A recent client lacked concern about building software regularly and successfully. In his mind, build failures were equal to the annoyance of a hobbled horse: something resolved easily when a release date approached.Ben Franklin

But this same chain of events could be applied to the software business. My crude version of the poem – adopted for software development – lacks the poetic prowess of Mr. Franklin. Hopefully, though, it illustrates a point.

FOR WANT OF A BUILD

For want of a build, a test case was not executed
For want of test case, a defect was not detected
For want of a defect report, a bad release was promoted
For want of a good release, a strategic customer was lost
For want of a customer, a development team was reduced
For want of developers, a product stagnated
For want of a product, a company was lost
And all for the want of a build…

We would all be well served to remember the potential impact of small problems as we consider where to spend our resources. Little annoyances like failed builds or test cases can be very early indicators that you are “losing the war” in your development efforts.

How important are the little annoyances in your software organization? Do you get concerned if a particular build effort fails? Do you have developer test cases? Are they executed regularly? Who gets heartburn if they fail?

Developer Testing and /Glover and Business Perspectives16 Jul 2007 08:33 pm

Behavior driven development (BDD) is an evolutionary result of test driven development (TDD) in the sense that rather than thinking in terms of tests (which have the tendency to make you think after the fact) you can more easily think in terms of a specification. By thinking about an application’s specification or behavior, it becomes easier to validate things early– in fact, when thinking in terms of a specification, it becomes quite easy to write things upfront.

To take a simple example, imagine a customer has asked that you create some sort of validation service for the ordering flow of their online business. Specifically, customers keep mistyping zip codes, which unfortunately delays the shipping process (which happens to cause customers to complain and use up valuable customer service representatives’ time). Consequently, the customer believes this small improvement will save the company money. It is a simple job that won’t take long (but the consequences for messing it up are rather large).

Wanting to be agile, I want to get something quickly in front of the customer– but rather than jumping into the coding process, I’ll begin to specify behavior à la BDD (in this case, JBehave). At a minimum, it is decided that I’ll need an interface, which provides a simple contract:

public interface Validatable {
  boolean validate(String value);
}

For a given String instance, an implementing class will return true or false based upon the validation requirements.

Next, I can specify a quick and dirty specification class (which I can show to my customer, if they speak code) that outlines a few, albeit sunny-day scenario, methods:

public class ZipCodeValidationBehavior extends UsingMiniMock{
 public void shouldAcceptInvalidZipCode(){}
 public void shouldDenyInvalidZipCode(){}
}

Note how this class doesn’t use the term ‘test’ — rather, the phrase ’should’ is utilized, because it turns out to be a bit more natural. Should equates to behavior, which is what I’m focused on at the moment.

As I haven’t actually coded a the business class yet, I’ll use JBehave’s mocking library to roughly specify my intended behavior. For example, given what I believe is a good zip code, the validation service should return true and consequently, given a bad zip code, the service should reject it.

To mock things easily, I create a simple helper method that returns a mock instance of the Validatable interface:

private Validatable getValidatable(boolean returnValue) {
 Mock validator = this.mock(Validatable.class);

 validator.expects("validate").with(new Matcher() {
  public boolean matches(Object arg) {
   return arg instanceof String;
  };
 }).atLeastOnce().will(returnValue(returnValue));

 return (Validatable) validator;
}

This method creates a Mock instance and specifies that the validate method will return what ever value was requested at instantiation time (either true or false, in this case). In addition, the method specifies that the mock’s validate method may be called with a String as an argument (there is probably an easier way to specify this without having to create a new Matcher type, but I’ve yet to figure that out) and may be called more than once.

Keep in mind, the point of this mocking exercise is to help me flesh out my desired behavior– once things are kosher, I can presumably remove the mock and use the real object (which will immediately be verified with the behavior methods I’m about to implement).

I can now implement the shouldAcceptInvalidZipCode method like so:

public void shouldAcceptInvalidZipCode() {
 List<String> goodzips = Arrays.asList("22101", "22101-5100");
 Validatable validator = this.getValidatable(true);
 for (String zip : goodzips) {
  boolean value = validator.validate(zip);
  ensureThat(value, eq(true));
 }
}

As you can see, a List of what I believe are valid zip codes is looped over and the mock is utilized as expected– true is returned every time.

I can also implement the shouldDenyInvalidZipCode method as follows:

public void shouldDenyInvalidZipCode() {
 List<String> badzips = Arrays.asList("221o1", "22101-100");
 Validatable validator = this.getValidatable(false);
 for (String zip : badzips) {
  boolean value = validator.validate(zip);
  ensureThat(value, eq(false));
 }
}

Thus far, I haven’t written a line of real business code, but I’ve now established the behavior I intend to write. I can run this behavior via JBehave’s runner and see the veritable green bar:

..
Time: 0.046s
Total: 2. Success!

What’s more, I can even go over this behavior with my customer or even with the QA department, business analysts, etc– it doesn’t really matter and the intent is the same– does this behavior work according to your specification (in this case, your specification of a valid or invalid zip code?).

Assuming everyone in onboard, I can move forward, or if things are not correct according to a stake holder, I can make fixes and I haven’t really lost much– a few cycles in JBehave, but I haven’t yet written any real code.

If things are good to go forward, I can implement the Validatable interface with a real class that hopefully validates zip codes:

public class ZipCodeValidator implements Validatable{
 private String zipRegEx = "^\d{5}([\-]\d{4})?$";
 private Pattern pattern; 

 public ZipCodeValidator() throws Exception {
  this.pattern = Pattern.compile(this.zipRegEx);
 }  

 public boolean validate(String value) {
  return this.pattern.matcher(value).matches();
 }
}

With my class implemented, I can now refactor my behavior class and plug in the real deal. Once I’ve done that, I can rerun the behavior methods to verify things work as intended. First, I’ll refactor the getValidatable method like so:

private Validatable getValidatable(){
 return new ZipCodeValidator();
}

Then, I need to fix each behavior method to invoke the proper getValidatable method; once that’s finished, I need to rerun the behavior class and voilà, things work as planned!

..
Time: 0.024s
Total: 2. Success!

As you hopefully can see through this example, BDD is an efficient way to drive the development of features in a rapid manner by communicating behavior rather than tests, which as I’ve found is a rather simple shift in thinking that opens the door to a wider audience of acceptance. Don’t get me wrong– I absolutely love writing tests in JUnit and TestNG, but I find these frameworks are a bit hard to get people to adopt upfront. No doubt, these frameworks offer a huge benefit when it comes to larger scale testing, such as component and system testing where large swaths of code are being verified.

Next Page »