Java

Autowired JUnit Tests with Spring 2.5

posted on 05 Jan 2009 09:15 by sonicneo  in Java

Spring 2.5 ships with great support for integration testing through the classes in the org.springframework.test package. These classes allow you to dependency inject your test cases off of your existing Spring configuration, either by using your production Spring configuration file or one you've defined especially for the test case. This post explains how to annotate your JUnit 4 test cases to be autowired, but there's a lot more too the new spring-test.jar and it works with JUnit 3.8 also.

As setup for all the examples, let's assume there is a simple service that can return a String to you. Imaginative, huh?
public class MyService {
private final String name;
public MyService(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
This service is defined in a Spring XML configuration file as:
    
To have Spring dependency inject our test case, we're going to have to annotate it with a little information. We'll use the standard JUnit @RunWith annotation to tell JUnit to use the Spring TestRunner, the Spring @ContextConfiguration annotation to indicate the TestCase needs injection, and the Spring @Autowired annotation to inject the MyService field by type.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public final class SimpleAutowireTest {
@Autowired
private MyService service;
@Test
public void testServiceName() {
assertEquals("simple service", service.getName());
}
} 
There are a variety of ways to have Spring run your test. Besides SpringJUnit4ClassRunner.class there are also abstract TestCase objects you can inherit from, including some that will expose the ApplicationContext to you. By default, the spring configuration file for the test case will be [TestName]-context.xml. You can easily override this to point the test at your production configuration file. Also, the @Autowired annotation autowires the field by type. In the case of conflicts, you can specify the bean name using the @Qualifier annotation. Consider the following Spring configuration where there are two beans of type MyService in a file named applicationContext.xml:
    
The JUnit test now requires the @Qualifier field annotation and a configuration file location as an @ContextConfiguration parameter:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"applicationContext.xml"})
public final class AdvancedAutowireTest {
@Autowired
@Qualifier("deliveryService")
private MyService service;
@Test
public void testServiceName() {
assertEquals("delivery service", service.getName());
}
}
To note: if you point the test to the production Spring configuration, then you're running integration tests and not unit tests. Integration tests are valuable and necessary, but are not always a wholesale replacement of unit tests. There's still value in isolation testing each of the components with mock dependencies. What I like about using Spring for the integration tests is that it validates the Spring mapping at test time. On my projects, we occasionally have the unit tests all passing but the Spring configuration contains a circular dependency, and we don't find out until the build hits QA. A Spring integration test pushes up error time to the test phase, when a developer can take quick action and long before QA is held up.

As is standard with JUnit, each test method runs within its own instance of the TestCase. However, the Spring TestRunner will only create one ApplicationContext for all the instances of the test method. This means that if you're test method destroys the state of a singleton bean, then downstream tests methods using that bean will fail. The way to work around this is to annotate your method with the @DirtiesContext annotation. This tells the Spring TestRunner to reload the context between test methods. For instance, these tests will pass when annotated, but fail when not:
    @Autowired
private MyConfigurableService service;
@Test
@DirtiesContext
public void testServiceName1() {
assertEquals("configurable service", service.getName());
service.setName("Updating Name");
}
@Test
@DirtiesContext
public void testServiceName2() {
assertEquals("configurable service", service.getName());
service.setName("Updating Name");
}

There's a lot more in spring-test, but this is a good starting point. The transaction annotations look especially promising, including the ability to open and rollback transactions per method. The only reference I know for spring-test is the Javadoc at http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/test/package-summary.html. Those looking for a Spring starter lesson might consult the DZone RefCard.

The dependencies for spring-test are: junit, spring-context, spring-core, spring-beans, spring-tx, and commons-logging. A sample Gradle script for your build is at href="http://svn.assembla.com/svn/SampleCode/spring-test/build.gradle.
All the code for this post (including Gradle build script and IDEA project) is posted at http://svn.assembla.com/svn/SampleCode/spring-test/ and can be downloaded through subversion with the following command:
svn co http://svn.assembla.com/svn/SampleCode/spring-test

 

source : http://hamletdarcy.blogspot.com/search/label/Spring

edit @ 5 Jan 2009 09:17:01 by sonicneo

อย่าง ที่พอจะทราบกันแล้วว่า  ถ้าเราต้องการให้ equals() ของคลาสที่เราเขียนขึ้นเองทำการเปรียบเทียบว่า object เท่ากันหรือไม่ โดยดูจากค่าใน object นั้น แทนที่จะทำการเปรียบเทียบโดยใช้ค่า reference ของ object (คือเปรียบเทียบว่าเป็น object เดียวกันหรือไม่) เราต้องทำการ override equals() พร้อมกับกำหนดวิธีการทำงานแบบที่เราต้องการเอง วิธีการ override equals() อย่างง่าย มีขั้นตอนดังนี้

1. เพิ่ม equals() method declaration เข้าไปในคลาสที่เราเขียนขึ้น ดังนี้

public boolean equals(Object o) {

}

2. ทำการตรวจสอบชนิดของ object ที่รับมาว่าเป็น object ของคลาสที่เราเขียนหรือไม่ โดยใช้ operator instanceof  ถ้า object ที่รับมาไม่ใช่ object ของคลาสที่เราเขียน ให้ return ค่าเป็น false ดังนี้

if (!(o instanceof MyClass))

   return false;

3. ทำการ cast object ที่รับมาให้เป็นชนิดของคลาสที่เราเขียน ดังนี้

MyClass c = (MyClass) o;

4. ทำการเปรียบเทียบค่าแต่ล่ะตัวของ object ทั้งสองว่าเท่ากันหรือไม่ ถ้าค่าเท่ากันให้ return true แต่ถ้าไม่เท่ากันให้ return false ในการเปรียบเทียบค่านั้น มีหลักดังนี้

  • ถ้าค่านั้นเป็นชนิดข้อมูล byte, short, int, long, char ให้ใช้ operator == ในการเปรียบเทียบ
  • ถ้าค่านั้นเป็นชนิดข้อมูล float ให้แปลงค่า float ให้เป็น int ก่อน โดยใช้ Float.floatToIntBits() แล้วเปรียบเทียบค่าที่ได้โดยใช้ operator == อีกที
  • ถ้าค่านั้นเป็นชนิดข้อมูล double ให้แปลงค่า double ให้เป็น long ก่อน โดยใช้ Double.doubleToLongBits() แล้วเปรียบเทียบค่าที่ได้โดยใช้ operator == อีกที
  • ถ้าค่านั้นเป็น object ให้เปรียบเทียบค่าโดยการเรียกใช้ equals() ของคลาสนั้น
  • ถ้าค่านั้นเป็น array ให้ทำการเปรียบเทียบค่าแต่ล่ะตัวภายใน array นั้น โดยใช้หลักการที่อธิบายไว้ข้างต้น

ในการเปรียบเทียบค่าของ object นั้น ให้พยายามเปรียบเทียบค่าที่มีโอกาสไม่เท่ากันมากที่สุดก่อน โดยเรียงลำดับแบบนี้จากมากไปหาน้อย เพราะจะได้ไม่ต้องเสียเวลาเปรียบเทียบค่าอื่น ๆ

5. ตรวจสอบว่าการทำงานของ equals() ที่เรากำหนดขึ้นนั้นเป็นไปตาม general contract หรือสัญญาที่กำหนดไว้ของ equals() หรือไม่  general contract ของ equals() ถูกกำหนดไว้ดังนี้

  • reflexive  สำหรับ object ตัวใดตัวหนึ่ง การเปรียบเทียบกับตัวเองจะต้องเท่ากันเสมอ
  • symmetric สำหรับ object สองตัว x, y ที่นำมาเปรียบเทียบ ถ้า x เท่ากับ y  y จะต้องเท่ากับ x ด้วย
  • transitive สำหรับ object สามตัว x, y, z ที่นำมาเปรียบเทียบกัน ถ้า x เท่ากับ y และ y เท่ากับ z แล้ว x จะต้องเท่ากับ z ด้วย
  • consistent ในการเรียกใช้งาน equals() หลาย ๆ ครั้ง ผลลัพท์ที่ได้จะต้องเหมือนเดิม ถ้าค่าของ object นั้นไม่มีการเปลี่ยนแปลง
  • ถ้าเปรียบเทียบ object กับ null จะต้องได้ false เสมอ

สังเกตว่าคุณสมบัติ reflexive, symmetic และ transitive เป็นคุณสมบัติของสิ่งที่เรียกในทางคณิตศาสตร์ว่า equivalence relation

6. เมื่อไหร่ก็ตามที่เราทำการ override equals() เราจะต้องทำการ override hashCode() ด้วยเสมอ ทั้งนี้ก็เพื่อรักษาให้ hashCode() ของคลาสที่เราเขียนขึ้นนั้นเป็นไปตาม general contract หรือข้อตกลงของ hashCode() ที่ถูกกำหนดไว้ว่า object ที่เท่ากัน จะต้องมีค่าของ hash code ที่เท่ากันด้วย (แต่ object ที่ไม่เท่ากันไม่จำเป็นต้องมีค่าของ hash code ที่เหมือนกัน) นอกจากนี้การ override hashCode() อย่างถูกต้อง จะทำให้เราสามารถใช้งาน object ของคลาสที่เราเขียนกับคลาสที่มีการใช้ค่า hash code ในการทำงาน อย่างเช่น HashTable, HashMap และ HashSet ได้อย่างถูกต้อง รายละเอียดการ override hashCode() สามารถอ่านได้จากบทความ "วิธีการ override hashCode() อย่างง่าย"

Example

public class Employee {
   private String _name;  // ชื่อ
   private int _age;  // อายุ
   private double _salary;   // เงินเดือน
   
   public Employee(String name, int age, double salary) {
      _name = name;
      _age = age;
      _salary = salary;
   }
  public boolean equals(Object o) {  // (1) เพิ่ม method declaration เพื่อ override equals()
     if (!(o instanceof Employee))  // (2) ตรวจสอบว่าเป็น object ของคลาสที่เราเขียน
        return false;
      
     Employee e = (Employee) o;  // (3) cast object ที่รับมาให้เป็นชนิดของคลาสที่เราเขียน
     // (4) เปรียบเทียบค่าภายใน object แต่ล่ะค่าว่าเท่ากันหรือไม่
     return _name.equals(e._name) && _age == e._age && Double.doubleToLongBits(_salary) == 
Double.doubleToLongBits(e._salary);
  }
   public static void main(String[] args) {
        Employee e1 = new Employee("John", 20, 25000.0);
        Employee e2 = new Employee("John", 20, 25000.0);
 
        System.out.println("e1 equals e2 ? = " + e1.equals(e2));
   }
}

อย่าง ที่พอจะทราบกันแล้วว่า เมื่อไหร่ก็ตามที่เราทำการ override equals() แล้ว เราต้องทำการ override hashCode() ด้วยเสมอ เพื่อรักษาข้อตกลง (contract) ของ hashCode() ที่ว่าทุก object ที่เหมือนหรือเท่ากันจากการทดสอบด้วย equals() จะต้องมีค่า hash code เท่ากันเสมอ

ทั้งนี้ก็เพราะว่า วิธีการทำงาน (implementation) ของ hashCode() ที่ได้รับสืบทอดมาจาก Object จะให้ค่า hash code ที่ไม่ได้ขึ้นอยู่กับค่าข้อมูลของ instance variable ของ object  ค่าที่ได้เป็นเพียงค่า integer ตัวหนึ่งสำหรับ object นั้น ทำให้ object สองตัวที่ถึงแม้จะเปรียบเทียบแล้วว่าเท่ากันด้วย equals() แต่ก็มี hash code ต่างกัน เมื่อนำ object นี้ไปใช้ใน HashMap หรือ Hashtable จะทำให้ทำงานผิดพลาดได้

ว่าแต่ hash code คืออะไรกัน ? hash code ก็เป็นเพียงค่า integer ค่าหนึ่งที่ได้จากการทำ hashing กับข้อมูลชุดหนึ่ง (คือการนำค่าของข้อมูลชุดหนึ่ง อย่างเช่น ชื่อ ไปผ่าน hashing function หรือ algorithm ที่ใช้สร้างค่า integer ทำให้ได้ค่า integer ออกมาค่าหนึ่ง ที่จะใช้แทนตัวข้อมูลนั้นได้ โดยมีหลักสำคัญอยู่ว่า ถ้าเป็นข้อมูลชุดเดียวกัน จะต้องมีค่า hash code เท่ากันเสมอ) ค่า hash code นี้จะมีความสำคัญอย่างมาก เมื่อเราต้องใช้งาน data structure ที่มีการทำงานโดยอาศัยเรื่องของ hashing อย่างเช่น HashMap, HashSet และ Hashtable

ขั้นตอนการ override hashCode() อย่างง่าย มีดังนี้

1. ทำการ override hashCode() ที่ได้รับสืบทอดมาจาก Object โดยเพิ่ม method declaration เข้าไปในคลาสที่เราเขียนขึ้น ดังนี้

public int hashCode() {
}

2. ทำการคำนวณหาค่า hash code จากค่าของตัวแปร instance variable ทั้งหมดที่มีในคลาสที่เราเขียน (ตัวแปรเหล่านี้จะต้องเป็นตัวแปรที่เราใช้ใน การเปรียบเทียบของ equals() ด้วย) โดยใช้วิธีการคำนวณหาค่า hash code ที่อธิบายไว้ใน [Bloch2001] ดังนี้

2.1 ให้ค่าเริ่มต้นกับ hash code ผลลัพท์ เป็นค่า integer อะไรก็ได้ อย่างเช่น 17 โดยเก็บไว้ในตัวแปร integer ตัวหนึ่ง อย่างเช่น result

2.2 หาค่า hash code ของแต่ล่ะ instance variable ของคลาสที่เราเขียน เพื่อนำมาคำนวณร่วมกับค่าเริ่มต้นของ hash code ผลลัพท์ ที่เก็บไว้ในตัวแปร result  วิธีการหาค่า hash code ของแต่ล่ะ instance variable มีดังนี้

  • ถ้าเป็นตัวแปรชนิด boolean ให้หาค่า hash code จาก (f ? 0 :1)
  • ถ้าเป็นตัวแปรชนิด bye, char, short, int ให้หาค่า hash code จาก (int) f
  • ถ้าเป็นตัวแปรชนิด long ให้หาค่า hash code จาก (int) (f ^ (f >>>  32))
  • ถ้าเป็นตัวแปรชนิด float ให้หาค่า hash code จาก Float.floatToIntBits(f)
  • ถ้าเป็นตัวแปรชนิด double ให้เริ่มจากหา Double.doubleToLongBits(f) ก่อน แล้วทำการหาค่า hash code โดยใช้วิธีการหาค่า hash code ของตัวแปรชนิด long อีกที
  • ถ้าตัวแปรเป็น reference ของ object ให้หาค่า hash code จากการเรียก hashCode() ของ object นั้น ในกรณีที่ reference นั้นเป็น null ให้ ค่า hash code ที่ได้เป็น 0 หรือค่าคงที่อื่น ๆ
  • ถ้าตัวแปรนั้นเป็น array ให้มองว่าสมาชิกแต่ล่ะตัวใน array นั้นก็เป็นเหมือนตัวแปรตัวหนึ่ง ให้ใช้หลักการข้างต้นในการหาค่า hash code ของสมาชิกแต่ล่ะตัว

2.3 ให้นำค่า hash code ของ instance variable ที่คำนวณได้จาก (2.2) มาคำนวณร่วมกับตัวแปร result ดังนี้

result = result * 37 + c;   // ให้ c เป็นค่า hash code ของตัวแปรที่คำนวณได้จาก (2.2)

2.4 หาค่า hash code ของแต่ล่ะตัวแปรในคลาส แล้วนำมาคำนวณร่วมกับตัวแปร result จนครบทุกตัวแปรในคลาส ค่าที่ได้จะเป็นค่า hash code ผลลัพท์ ให้ค่าผลลัพท์ที่ได้เป็นค่าที่จะใช้ return สำหรับ hashCode()

3. ตรวจสอบว่าค่า hash code ที่ได้จาก hashCode() เป็นไปตามข้อตกลง (contract) ที่กำหนดไว้สำหรับ hashCode() ดังนี้

  • เมื่อเรียกใช้ hashCode() ของ object ตัวหนึ่งมากกว่า 1 ครั้ง ค่าที่ได้จะต้องเป็นค่าเดิมเสมอ กำหนดให้ค่า instance variable ภายใน object นั้นไม่มีการเปลี่ยนแปลง
  • เมื่อเปรียบเทียบ object สองตัวด้วย equals() แล้วปรากฏว่าเท่ากัน ค่า hash code ที่ได้จากการเรียก hashCode() ของแต่ล่ะ object จะต้องเป็นค่าเดียวกัน
  • ถ้าเปรียบเทียบ object สองตัวด้วย equals() แล้วปรากฏว่าไม่เท่ากัน ค่า hash code ที่ได้จากการเรียก hashCode() ของแต่ล่ะ object ไม่จำเป็นต้องเท่ากันก็ได้ แต่การที่ object ที่ไม่เท่ากันมีค่า hash code ที่ต่างกันจะช่วยทำให้ data structure อย่างเช่น HashMap, HashSet, Hashtable ทำงานได้อย่างมีประสิทธิภาพมากขึ้น

Example

จากตัวอย่างของบทความ "วิธีการ override equals() อย่างง่าย" เราสามารถ override hashCode() ของ Employee ได้ดังนี้

import java.util.*;
public class Employee {
   private String _name;  // ชื่อ
   private int _age;  // อายุ
   private double _salary;   // เงินเดือน
   
   public Employee(String name, int age, double salary) {
      _name = name;
      _age = age;
      _salary = salary;
   }
  public boolean equals(Object o) {  // เพิ่ม method declaration เพื่อ override equals()
     if (!(o instanceof Employee))  // (2) ตรวจสอบว่าเป็น object ของคลาสที่เราเขียน
        return false;
      
     Employee e = (Employee) o;  // (3) cast object ที่รับมาให้เป็นชนิดของคลาสที่เราเขียน
     // (4) เปรียบเทียบค่าภายใน object แต่ล่ะค่าว่าเท่ากันหรือไม่
     return _name.equals(e._name) && _age == e._age && Double.doubleToLongBits(_salary) == 
Double.doubleToLongBits(e._salary);
  }
  public int hashCode() {
     int result = 17;  // ให้ค่าเริ่มต้นกับค่า hash code ผลลัพท์
             // หาค่า hash code ของ _name แล้วนำมาคำนวณร่วมกับ result ตามสมการใน (2.3)
     result = 37 * result + _name.hashCode();       
     result = 37 * result + _age;  // หาค่า hash code ของ _age แล้วนำมาคำนวณร่วมกับ result 
     
     // หาค่า hash code ของ _salary แล้วนำมาคำนวณร่วมกับ result 
     long temp = Double.doubleToLongBits(_salary); 
     result = 37 * result + ((int) (temp ^ (temp >>> 32)));
     // ค่าผลลัพท์สุดท้ายที่ได้จะเป็นค่า hash code ของ object
     return result;
  }
   public static void main(String[] args) {
        Employee e1 = new Employee("John", 20, 25000.0);
        Employee e2 = new Employee("John", 20, 25000.0);
  
        // ทดลองใช้งาน Employee กับ HashMap
        HashMap map = new HashMap(); 
        map.put(e1, "John"); // ใส่ e1 ใน HashMap
        
        System.out.println(map.get(e2)); // ทดลองดึง e1 จาก HashMap โดยใช้ e2 ในการหา
   }
}

Top 10 differences between Java and C#

posted on 17 Sep 2008 08:49 by sonicneo  in Java

My latest transition from Java to C# left me scratching my head and scrambling to find the differences.  Don’t get me wrong — they are very similar, but some key syntax and philosophical differences set these two languages apart.  Below are my top 10 differences that I wish someone told me before I pulled out yet more hair.

Gotcha #10 - Give me my standard output!
Gotcha #9 - Namespaces == Freedom
Gotcha #8 - What happened to super?
Gotcha #7 - Chaining constructors to a base constructor
Gotcha #6 - Dagnabit, how do I inherit?
Gotcha #5 - Why don’t constants remain constant?
Gotcha #4 - Where is ArrayList, Vector or Hashtable?
Gotcha #3 - Of Accessors and Mutators (Getters and Setters)
Gotcha #2 - I can’t override!?
And the #1 gotcha…

Gotcha #10 - Give me my standard output!

This may not seem like a big deal, but when I’m first getting my head in a language, I want to be able to debug.  With everything so new and shiny, I don’t want to hear about the debugger yet, I don’t care about the fancy message boxes, just tell me how to get something on standard output!

In C#, the code looks like this:

  1. Console.WriteLine("your string here");  

Gotcha #9 - Namespaces ==  Freedom

In Java, the package hierarchical structure mirrored the directory hierarchical structure.  This made sense to a degree, but then why didn’t Sun just auto-derive the package structure?  Anyway, Microsoft has freed us from this constraint.  The C# package structure is defined using namespaces (just like Java), but the namespaces do NOT have to reflect the directory structure.

Gotcha #8 - What happened to super?

Slight renaming of keywords drives me bonkers!  Substitute Java’s super keyword with base.

Gotcha #7 - Chaining constructors to a base constructor

In Java, I often created a set of constructors with differing parameters that all reference a common all-powerful constructor.  In other words, I created a set of overloaded constructors that basically just called a constructor that did the bulk of the work.  This is called constructor chaining and normally leads to easier to maintain code.  In Java, the this(…) statement is used to call the constructor.  In C#, this is done right up in the method signature.

  1. public MyConstructor(int i) : this(i, -1)  
  2. {  
  3.     ...  
  4. }  
  5.   
  6. public MyConstructor(int i, int j)  
  7. {  
  8.     ...  
  9. }  

Gotcha #6 - Dagnabit, how do I inherit?

In Java, the keyword extends is use to inherit from a parent class, and the keyword implements is use to inherit an interface.  In C#, the distinction does not exist and it’s all done in the method signature.

  1. public class MyClass : MyParentClass  
  2. {  
  3.     ...  
  4. }  

Gotcha #5 - Why don’t constants remain constant?

Well of course they do!  Just not among different languages.  In Java, I normally defined global constants using public static final.  In C#, the static keyword does exist (final does not), but you can define constants like this:

  1. public const MyConstant = 101;  

When the constant needs to be initialized at run-time (for example in a constructor), use the readonly keyword instead of const.

Gotcha #4 - Where is ArrayList, Vector or Hashtable?

In Java, these guys were my staples.  Pre-built dynamic arrays and look-up tables decrease development time and makes my life a whole lot easier, but where are they in C#? C# has an ArrayList, but it doesn’t make use of generics. Instead, I like to use

  1. System.Collections.Generic.List<>  

Unfortunately, it’s not thread-safe like C#’s ArrayList or Java’s Vector . C# also has a Hashtable; the generic version is

  1. System.Collections.Generic.Dictionary<>  

Gotcha #3 - Of Accessors and Mutators (Getters and Setters)

As long as methods exist in classes, accessors and mutators will exist.  However, C# largely replaces them with class properties. Instead of the traditional getSomeInteger() and setSomeInteger(), we use properties!

  1. public class SomeClass  
  2. {  
  3.     int someInteger = 42;  
  4.   
  5.     public int SomeInteger  
  6.     {  
  7.         get { return this.someInteger; }  
  8.         set { this.someInteger = value; }  
  9.     }  
  10.   
  11.     public void Main(string[] args)  
  12.     {  
  13.         SomeClass c = new SomeClass();  
  14.         Console.WriteLine(c.SomeInteger);  
  15.         c.SomeInteger = 420;  
  16.     }  
  17. }  

this.someInteger is a class variable, and value is the new integer.

Gotcha #2 - I can’t override!?

At this point, we’ve transcended the syntax differences and we’ve entered into more philosophical choices that the Microsoft team made. In Java, all methods are by default virtual and you can override them. In C#, all methods are non-virtual. To override a method in the parent class, make sure the method of the parent class is defined as virtual using the virtual keyword.

  1. class MyParentClass  
  2. {  
  3.     public virtual void MyMethod() { ... }  
  4. }  

In the child class, the method must use the override keyword.

  1. class MyChildClass : MyParentClass  
  2. {  
  3.     public override void MyMethod() { ... }  
  4. }  

And the #1 gotcha…

I remember when I first learned Java, and everyone was saying how Java made everything an object. How Java forced you to make classes for everything. This turns out to be partially true. It is necessary to make classes.  However, primitives are not objects. In C#, even what were considered primitives in Java are objects in C#.  Absolutely everything descends from System.Object.  This choice by the C# team allows for greater consistency and for such things as automatic boxing/unboxing.

Address

ITIT CO. LTD
BANGKOK 10120
Phone: 6826350 Site Code: TH0
900/2 SVOA TOWER
5TH FLOOR RAMA III ROAD
BANGPONGPANG YANNAWA

DATAMAT EDUCATION CO., LTD
BANGKOK 10110
Phone: 2310 5151 Site Code: TH10
219/14-15 ASOKE TOWERS,
SUKHUMVIT 21 ROAD,
(ASOKE) NORTH KLONGTOEY,
WATTANA,

FIRST LOGIC COMPANY LIMITED
BANGKOK, Bangkok 10500
Phone: 6850414 Site Code: TH11
15th Floor., 92/40
SATHORN THANI BUILDING 2
NORTH SATHORN RD
SILOM, BANGRAK

IVERSON COMPUTER ASSOCIATES
BANGKOK 10110
Phone: 254 3641-2 Site Code: TH4
140 ONE PACIFIC PLACE
ROOM 1006,1209
SUKHUMVIT ROAD
KLONGTOEY

NECTEC
BANGKOK 10400
Phone: 642 5001-10 Site Code: TH5
21 FL GYPSUM METROPOLITAN
TOWER 539/2 SRIAYUDHYA RD
RAJTHEVI

THE ENTERPRISE RESOURCES TRAIN
BANGKOK 10320
Phone: 718 1599 Site Code: TH7
3RD FLOOR CHARN ISSARA TOWER 2
NEW PETCHBURI ROAD 2922/135-136
ROOM 331-332 BANGKAPI HUAYKWANG

CERTIFIED TECHNICAL TRAINING
BANGKOK 10110
Phone: 23026614 Site Code: THB
253 (UNIF), 27th Floor,
Sukhumvit 21 (Asoke) Road
North-Klongtoey, Wattana

BANGKOK ADVANCED LEARNING
BANGKOK 10400
Phone: 298 0277-82 Site Code: THC
16TH FLOOR SM TOWER BUILDING
979/30 PHAHOLYOTHIN ROAD
SAMSENNAI

ITIT CO LTD - SIAM COMPUTER
AND LANGUAGE INSTITUTE
BANGKOK 10400
Phone: 2472345 Site Code: TH0M4

471/19 RATCHAWITHI RD
RAJTHEWEE

ITIT CO LTD - SRIPATUM UNIVERSITY
BANGKOK 10900
Phone: 025791111EXT2250 Site Code: TH0M7
61 Phaholyothin rd, BUILDING 5
Sripatum University
Floor 11th ICT SERVICE CENTER
Jatujak

Isonet Co.Ltd
Bangkok 10320
Phone: 66264122008 Site Code: TH18
15th Floor, RS Tower
121/56 Ratchadapisek road
Dindaeng

Synetech and Media co.Ltd
bangkok
Phone: 29350016 Site Code: TH30
2753-7 Ladphrao 99-101

ESI Language Centers
Bangkok, Bangkok 10900
Phone: 25615090 Site Code: TH35
85 Ngamwongwan Road
Lardyao Jatujak

Vnohow (Thailand) Co.,Ltd
Bangkok, Bangkok 10500
Phone: 6343287 Site Code: TH36
138 Boonmitr Building,
11th Floor, Room B1-B2,
Silom Road, Suriyawong,
Bangrak

ITIT CO LTD (MOBILE- CHIANGMAI)
Chiangmai 50200
Phone: 2275002 Site Code: TH0M1
A&A Co., Ltd 248/55-56 Maneenoparat Rd.
Tambon Sripoom, Amphoe Muang

ITIT CO LTD (MOBILE - SONGKHLA)
HATYAI, Songkhla 90110
Phone: 74424776 Site Code: TH0M5
HATYAI UNIVERSITY
125/502
POLPHICHAI RD.,
SONGKHLA

ITIT CO LTD - BANGKOK (MOBILE-BANGKOK)
Kalasin 46230
Phone: 43860218 Site Code: TH0M
Kalasin Ratchapat University
Tumbon Songphuie Amphur
Kalasin-Somdej Rd.
Namon

ITIT CO LTD - RAJAMANGALA UNI
OF TECHNO SUVARNABHUMI
MUANG, Nonthaburi 11000
Phone: 9526773 Site Code: TH0M6

7/1 NONTHABURI RD
SUANYAI

ITIT CO LTD (MOBILE - PHITSANULOK)
MUANG PHISANULOK 65000
Phone: 261080 Site Code: TH0M2
Naresuan University 99 Moo 9
T Tapo A Muang PHISANULOK
NAKORNSAWAN RD

ExecuTrain of Bangkok
Silom, Bangkok 10500
Phone: 263115002 Site Code: TH39
20th Floor, Liberty Square
287 Silom Rd
Bangkok