How to write junit test case for the program [closed]

I have a method which has external dependencies within the method. Please help me in writing a junit test case for the below program.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> @Override
public void methodToTest(String user){
//fetch the values from the properties file. Config class has a static method called
//getProperty which reads the values from the environment specific property file.
String url = Config.getProperty("serviceurl");
String username = Config.getProperty("serviceusername");
String password = Config.getProperty("servicepassword");
//Connect to an external service.
Service service = new Service(url, username, password);
//invoke the method on the service.
String returnValue = service.registerUser(user);
if (returnValue.equals("failure")){
throw new Exception("User could not be registered");
}
}
</code>
<code> @Override public void methodToTest(String user){ //fetch the values from the properties file. Config class has a static method called //getProperty which reads the values from the environment specific property file. String url = Config.getProperty("serviceurl"); String username = Config.getProperty("serviceusername"); String password = Config.getProperty("servicepassword"); //Connect to an external service. Service service = new Service(url, username, password); //invoke the method on the service. String returnValue = service.registerUser(user); if (returnValue.equals("failure")){ throw new Exception("User could not be registered"); } } </code>
    @Override
    public void methodToTest(String user){

      //fetch the values from the properties file. Config class has a static method called
      //getProperty which reads the values from the environment specific property file.
      String url = Config.getProperty("serviceurl");
      String username = Config.getProperty("serviceusername");
      String password = Config.getProperty("servicepassword");

      //Connect to an external service.
      Service service = new Service(url, username, password);

      //invoke the method on the service.
      String returnValue = service.registerUser(user);

      if (returnValue.equals("failure")){
        throw new Exception("User could not be registered");
      }
    }

Note:

  1. The method overrides the superclass method so that I cannot change the
    arguments to contain the url, username and password.
  2. The method also connects to an external service. which is environment specific. The
    environment details is taken from the properties file.

If it appears difficult to test a method, I suggest attempting to test the components of the method instead.

It looks like your code would benefit from a little bit of refactoring.
It appears that your method has too much responsibility. Try breaking the method down into smaller chunks.

I suggest taking a look at what actions are being enacted at each stage of the method, as opposed to testing the method as a whole.
By breaking down the method into smaller chunks you ensure that you are getting good test coverage and can easily drill-down into finding out which parts (if any) break.

Based on the small snippet you have provided and my assumptions of what you are trying to do, responsibilities include:

  1. Retrieval of the login details,
  2. Connecting to a service
  3. Adding a user.

These three different responsibilities should be tested independently and where one fails, it should be clear at which steps (if any of these) it failed.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public myClass extends myFoo {
Service service;
public myClass() {
//fetch the values from the properties file. Config class has a static method called
//getProperty which reads the values from the environment specific property file.
String url = Config.getProperty("serviceurl");
String username = Config.getProperty("serviceusername");
String password = Config.getProperty("servicepassword");
//Connect to an external service.
service = new Service(url, username, password); //Error handling??
}
@Override
public void registerUser(String user){
//invoke the method on the service.
String returnValue = service.registerUser(user);
if (returnValue.equals("failure")){
throw new Exception("User could not be registered");
}
}
}
</code>
<code>public myClass extends myFoo { Service service; public myClass() { //fetch the values from the properties file. Config class has a static method called //getProperty which reads the values from the environment specific property file. String url = Config.getProperty("serviceurl"); String username = Config.getProperty("serviceusername"); String password = Config.getProperty("servicepassword"); //Connect to an external service. service = new Service(url, username, password); //Error handling?? } @Override public void registerUser(String user){ //invoke the method on the service. String returnValue = service.registerUser(user); if (returnValue.equals("failure")){ throw new Exception("User could not be registered"); } } } </code>
public myClass extends myFoo {
    Service service;

    public myClass() {
      //fetch the values from the properties file. Config class has a static method called
      //getProperty which reads the values from the environment specific property file.
      String url = Config.getProperty("serviceurl");
      String username = Config.getProperty("serviceusername");
      String password = Config.getProperty("servicepassword");

      //Connect to an external service.
      service = new Service(url, username, password); //Error handling??
    }

    @Override
    public void registerUser(String user){
      //invoke the method on the service.
      String returnValue = service.registerUser(user);

      if (returnValue.equals("failure")){
        throw new Exception("User could not be registered");
      }
    }
}

Take a look at the above example. There are a few ways you can play with it and without knowing more I’m not sure which would be best for you, but essentially the method that registers a user doesn’t “care” about how the service is created or what the login details are – all it needs is a service to add the given user to.

I question whether the service needs to be a field and/or contained in the constructor – there’s no reason why it shouldn’t be moved into a method of its own:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public myClass extends myFoo {
@Override
public void registerUser(String user){
Service service = getService();
//invoke the method on the service.
String returnValue = service.registerUser(user);
if (returnValue.equals("failure")){
throw new Exception("User could not be registered");
}
}
//Would be contained within the superclass (eg if Config shared between all subclasses), else overridden via the subclass (eg if each subclass had a different Config)
protected Service getService() { //Error handling? eg throws InvalidCredentialsError? throws NetworkConnectionError? etc....
//fetch the values from the properties file. Config class has a static method called
//getProperty which reads the values from the environment specific property file.
String url = Config.getProperty("serviceurl");
String username = Config.getProperty("serviceusername");
String password = Config.getProperty("servicepassword");
//Connect to an external service.
service = new Service(url, username, password);
/**
if(service == null) {
throw new InvalidCredentialsError("The given url, username and password are invalid.");
}
**/
return service;
}
}
</code>
<code>public myClass extends myFoo { @Override public void registerUser(String user){ Service service = getService(); //invoke the method on the service. String returnValue = service.registerUser(user); if (returnValue.equals("failure")){ throw new Exception("User could not be registered"); } } //Would be contained within the superclass (eg if Config shared between all subclasses), else overridden via the subclass (eg if each subclass had a different Config) protected Service getService() { //Error handling? eg throws InvalidCredentialsError? throws NetworkConnectionError? etc.... //fetch the values from the properties file. Config class has a static method called //getProperty which reads the values from the environment specific property file. String url = Config.getProperty("serviceurl"); String username = Config.getProperty("serviceusername"); String password = Config.getProperty("servicepassword"); //Connect to an external service. service = new Service(url, username, password); /** if(service == null) { throw new InvalidCredentialsError("The given url, username and password are invalid."); } **/ return service; } } </code>
public myClass extends myFoo {
    @Override
    public void registerUser(String user){
      Service service = getService();

      //invoke the method on the service.
      String returnValue = service.registerUser(user);

      if (returnValue.equals("failure")){
        throw new Exception("User could not be registered");
      }
    }

    //Would be contained within the superclass (eg if Config shared between all subclasses), else overridden via the subclass (eg if each subclass had a different Config)
    protected Service getService() { //Error handling? eg throws InvalidCredentialsError? throws NetworkConnectionError? etc....
      //fetch the values from the properties file. Config class has a static method called
      //getProperty which reads the values from the environment specific property file.
      String url = Config.getProperty("serviceurl");
      String username = Config.getProperty("serviceusername");
      String password = Config.getProperty("servicepassword");

      //Connect to an external service.
      service = new Service(url, username, password);

      /**
      if(service == null) {
        throw new InvalidCredentialsError("The given url, username and password are invalid.");
      }
      **/

      return service;
    }
}

Based my assumptions of the responsibilities of the code, I would then break down your method into three (possibly four) sets of tests as follows:

  1. The first “action” is the retrieval – thoroughly test the Config.getProperty().
    If you are confident that this method works correctly, you may assume that the url/username/password values will be assigned correctly. Presumably there is also a Config.setProperty method – for these tests to pass, whatever value you pass into setProperty must be identical to the value you retrieve via Config.getProperty().

  2. The next “action” is to setup the Service().
    Test all variations of known correct/known incorrect (and potentially known malicious, see injection flaws)/empty string/null values for url/username/password.
    Without knowing more about the application I am not sure what the success/failure criteria are (perhaps an exception is thrown when an invalid url/username/password are passed into the constructor, but this begs the question of why it isn’t being thrown/caught in the code currently visible).

  3. The final “action” is to attempt the addition of a user.
    Looking at the method, I assume that the core functionality of the method you are attempting to test is the addition of a user. Assuming that set of tests #1 and set of tests #2 have passed, this should be as straightforward as passing in values that you expect to succeed (eg “Jim”), values that you expect to fail or aren’t sure about (null, empty string, extremely long strings?? etc) and ensuring that the value you expect to come back does actually come back.
    What I notice is that you state the service is an external service.
    If you trust the external service to have tested their code thoroughly, you may not need this step (in which case, skip straight to #4).

  4. A potential final test is to test the method itself.
    This would probably be identical to set of tests #3, but instead of testing the return value of the registerUser() method, you would be testing to see if the appropriate exception(s) are being thrown as opposed to testing the return value(s).

The next step is for you to write the actual JUnit test classes 😉

In addition to @kwah excelent (+1) answer you should encapsulate the external service into an interface that can be more easily mocked/simulated than the real service:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> //Connect to an external service.
IService service = getService(url, username, password);
//invoke the method on the service.
String returnValue = service.registerUser(user);
</code>
<code> //Connect to an external service. IService service = getService(url, username, password); //invoke the method on the service. String returnValue = service.registerUser(user); </code>
  //Connect to an external service.
  IService service = getService(url, username, password);

  //invoke the method on the service.
  String returnValue = service.registerUser(user);

Since the resources are external, in your case the Config and Service, it makes it a bit difficult to test. You basically have two options:

  1. Go with the flow and set up the external resources under your control if possible
  2. Refactor the code so that it is easier to mock the resources

Since the first one you clearly can’t do, we’ll go through the second one. Refactoring the code with each step fixing each dependency so that they are replaceable for the test:

Fixing Config dependency

I’m assuming that Config is a static resource, which means you need to be able to replace it somehow. Easiest is to add a new replaceable resource:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public interface IConfigResource {
String getProperty(String propertyName);
}
</code>
<code>public interface IConfigResource { String getProperty(String propertyName); } </code>
public interface IConfigResource {
    String getProperty(String propertyName);
}

Together with a handy dandy default static version of it:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public class DefaultConfigResource : IConfigResource {
public String getProperty(String propertyName) {
return Config.getProperty(propertyName);
}
}
</code>
<code>public class DefaultConfigResource : IConfigResource { public String getProperty(String propertyName) { return Config.getProperty(propertyName); } } </code>
public class DefaultConfigResource : IConfigResource {
    public String getProperty(String propertyName) {
        return Config.getProperty(propertyName);
    }
}

In your class you need to add/change the following so that the dependency can be injected for test:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>// The default is set at construction
private IConfigResource configResource = new DefaultConfigResource();
// Method used by the test to inject the config resource
public void setConfigResource(IConfigResource configResource) {
this.configResource = configResource;
}
</code>
<code>// The default is set at construction private IConfigResource configResource = new DefaultConfigResource(); // Method used by the test to inject the config resource public void setConfigResource(IConfigResource configResource) { this.configResource = configResource; } </code>
// The default is set at construction
private IConfigResource configResource = new DefaultConfigResource();

// Method used by the test to inject the config resource
public void setConfigResource(IConfigResource configResource) {
    this.configResource = configResource;
}

Now we can either use Mockito or manually handroll a mocked version of IConfigResource to test that your method is calling the config resource correctly, in the test below we use Mockito:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ClassUnderTest cut;
IConfigResource mockedResource;
@Before
public void setup() {
cut = ... ; // setup for class under test
// We mock with mockito and inject the resource
mockedResource = mock(IConfigResource.class);
cut.setConfigResource(mockedConfigResource);
}
@Test
public void callingMethod_ShouldGetValuesFromResource() {
// Arrange
// might change the return values to reflect the correct ones
when(mockedResource.getProperty("serviceurl"))
.thenReturn("correct service url");
when(mockedResource.getProperty("serviceusername"))
.thenReturn("correct service username");
when(mockedResource.getProperty("servicepassword"))
.thenReturn("correct service password");
// Act
cut.methodToTest("username");
// Assert, with mockito
verify(mockedResource).getProperty("serviceurl");
verify(mockedResource).getProperty("serviceusername");
verify(mockedResource).getProperty("servicepassword");
}
</code>
<code>ClassUnderTest cut; IConfigResource mockedResource; @Before public void setup() { cut = ... ; // setup for class under test // We mock with mockito and inject the resource mockedResource = mock(IConfigResource.class); cut.setConfigResource(mockedConfigResource); } @Test public void callingMethod_ShouldGetValuesFromResource() { // Arrange // might change the return values to reflect the correct ones when(mockedResource.getProperty("serviceurl")) .thenReturn("correct service url"); when(mockedResource.getProperty("serviceusername")) .thenReturn("correct service username"); when(mockedResource.getProperty("servicepassword")) .thenReturn("correct service password"); // Act cut.methodToTest("username"); // Assert, with mockito verify(mockedResource).getProperty("serviceurl"); verify(mockedResource).getProperty("serviceusername"); verify(mockedResource).getProperty("servicepassword"); } </code>
ClassUnderTest cut;
IConfigResource mockedResource;

@Before
public void setup() {
    cut = ... ; // setup for class under test

    // We mock with mockito and inject the resource
    mockedResource = mock(IConfigResource.class);
    cut.setConfigResource(mockedConfigResource);
}

@Test
public void callingMethod_ShouldGetValuesFromResource() {
    // Arrange
    // might change the return values to reflect the correct ones
    when(mockedResource.getProperty("serviceurl"))
        .thenReturn("correct service url");
    when(mockedResource.getProperty("serviceusername"))
        .thenReturn("correct service username");
    when(mockedResource.getProperty("servicepassword"))
        .thenReturn("correct service password");

    // Act
    cut.methodToTest("username");

    // Assert, with mockito
    verify(mockedResource).getProperty("serviceurl");
    verify(mockedResource).getProperty("serviceusername");
    verify(mockedResource).getProperty("servicepassword");
}

There, the Config part of the method should now be tested

Fixing Service dependency (and removing Config dependency as a bonus)

So we need something that needs to handle this part of the code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>//Connect to an external service.
Service service = new Service(url, username, password);
//invoke the method on the service.
String returnValue = service.registerUser(user);
</code>
<code>//Connect to an external service. Service service = new Service(url, username, password); //invoke the method on the service. String returnValue = service.registerUser(user); </code>
//Connect to an external service.
Service service = new Service(url, username, password);

//invoke the method on the service.
String returnValue = service.registerUser(user);

First the service needs to have a replaceable interface in order for us to be able to test that your method is calling service.registerUser(String). This should be easy:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public interface IService {
String registerUser(String userName);
}
</code>
<code>public interface IService { String registerUser(String userName); } </code>
public interface IService {
   String registerUser(String userName);
}

Your current service can implement this interface with ease, just add it to the class signature (since it should have the method already):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public class Service implements IService {
...
</code>
<code>public class Service implements IService { ... </code>
public class Service implements IService {
...

We also need something (a factory method of sorts) that can connect to the service and return something that looks like an IService. We can also add the config resource we’ve made above to make it a bit easier:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public interface IServiceConnector {
void setConfigResource(IConfigResource configResource);
// no need to have parameters, the config is injected above
IService getService();
}
</code>
<code>public interface IServiceConnector { void setConfigResource(IConfigResource configResource); // no need to have parameters, the config is injected above IService getService(); } </code>
public interface IServiceConnector {
    void setConfigResource(IConfigResource configResource);

    // no need to have parameters, the config is injected above
    IService getService();
}

The default implementation is easy, we can use the ConfigResource we used before:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public class DefaultServiceConnector {
IConfigResource configResource = new DefaultConfigResource();
public void setConfigResource(IConfigResource configResource) {
this.configResource = configResource;
}
public IService getService() {
String url = Config.getProperty("serviceurl");
String username = Config.getProperty("serviceusername");
String password = Config.getProperty("servicepassword");
return new Service(url, username, password);
}
}
</code>
<code>public class DefaultServiceConnector { IConfigResource configResource = new DefaultConfigResource(); public void setConfigResource(IConfigResource configResource) { this.configResource = configResource; } public IService getService() { String url = Config.getProperty("serviceurl"); String username = Config.getProperty("serviceusername"); String password = Config.getProperty("servicepassword"); return new Service(url, username, password); } } </code>
public class DefaultServiceConnector {
    IConfigResource configResource = new DefaultConfigResource();

    public void setConfigResource(IConfigResource configResource) {
        this.configResource = configResource;
    }

    public IService getService() {
        String url = Config.getProperty("serviceurl");
        String username = Config.getProperty("serviceusername");
        String password = Config.getProperty("servicepassword");

        return new Service(url, username, password);
    }
}

You can now move the test written above to be used as test for this connector class where the method under test is connectService(). Furthermore your original method under test should be easier now:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>IServiceConnector serviceConnector = new DefaultServiceConnector();
public void setServiceConnector(IServiceConnector serviceConnector) {
this.serviceConnector = serviceConnector;
}
@Override
public void methodToTest(String user) {
// ... Removed some code ...
//Connect to an external service.
Service service = serviceConnector.getService();
//invoke the method on the service.
String returnValue = service.registerUser(user);
if (returnValue.equals("failure")){
throw new Exception("User could not be registered");
}
}
</code>
<code>IServiceConnector serviceConnector = new DefaultServiceConnector(); public void setServiceConnector(IServiceConnector serviceConnector) { this.serviceConnector = serviceConnector; } @Override public void methodToTest(String user) { // ... Removed some code ... //Connect to an external service. Service service = serviceConnector.getService(); //invoke the method on the service. String returnValue = service.registerUser(user); if (returnValue.equals("failure")){ throw new Exception("User could not be registered"); } } </code>
IServiceConnector serviceConnector = new DefaultServiceConnector();

public void setServiceConnector(IServiceConnector serviceConnector) {
    this.serviceConnector = serviceConnector;
}

@Override
public void methodToTest(String user) {
  // ... Removed some code ...

  //Connect to an external service.
  Service service = serviceConnector.getService();

  //invoke the method on the service.
  String returnValue = service.registerUser(user);

    if (returnValue.equals("failure")){
      throw new Exception("User could not be registered");
    }
}

The test should look something like this now:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ClassUnderTest cut;
IServiceConnector mockedConnector;
IService mockedService;
@Before
public void setup() {
cut = ... ; // setup for class under test
// We mock with mockito and inject the resource
mockedConnector = mock(IServiceConnector.class);
cut.setServiceConnector(mockedConnector);
// We mock the service to be used
mockedService = mock(IService.class);
}
@Test
public void registerUser_ShouldRegisterToService() {
// Arrange
// might change the return values to reflect the correct ones
when(mockedConnector.getService())
.thenReturn(mockedService);
String newUsername = "newusername";
// Act
cut.methodToTest(newUsername);
// Assert, with mockito
// we only need to assert that the service registers the
// new user
verify(mockedService).registerUser(username);
}
</code>
<code>ClassUnderTest cut; IServiceConnector mockedConnector; IService mockedService; @Before public void setup() { cut = ... ; // setup for class under test // We mock with mockito and inject the resource mockedConnector = mock(IServiceConnector.class); cut.setServiceConnector(mockedConnector); // We mock the service to be used mockedService = mock(IService.class); } @Test public void registerUser_ShouldRegisterToService() { // Arrange // might change the return values to reflect the correct ones when(mockedConnector.getService()) .thenReturn(mockedService); String newUsername = "newusername"; // Act cut.methodToTest(newUsername); // Assert, with mockito // we only need to assert that the service registers the // new user verify(mockedService).registerUser(username); } </code>
ClassUnderTest cut;
IServiceConnector mockedConnector;
IService mockedService;

@Before
public void setup() {
    cut = ... ; // setup for class under test

    // We mock with mockito and inject the resource
    mockedConnector = mock(IServiceConnector.class);
    cut.setServiceConnector(mockedConnector);

    // We mock the service to be used
    mockedService = mock(IService.class);
}

@Test
public void registerUser_ShouldRegisterToService() {
    // Arrange
    // might change the return values to reflect the correct ones
    when(mockedConnector.getService())
        .thenReturn(mockedService);
    String newUsername = "newusername";

    // Act
    cut.methodToTest(newUsername);

    // Assert, with mockito
    // we only need to assert that the service registers the 
    // new user
    verify(mockedService).registerUser(username);
}

You can also test the exception throwing:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>// test the exception
@Test(expected = Exception.class)
public void registerUser_ThrowExceptionOnError() {
// Arrange
when(mockedConnector.getService())
.thenReturn(mockedService);
// return failure on any string
when(mockedService.registerUser(anyString))
.thenReturn("failure");
String newUsername = "newusername";
// Act
cut.methodToTest(newUsername);
// Assert
// Should throw exception and be checked with the
// expected parameter in test
}
</code>
<code>// test the exception @Test(expected = Exception.class) public void registerUser_ThrowExceptionOnError() { // Arrange when(mockedConnector.getService()) .thenReturn(mockedService); // return failure on any string when(mockedService.registerUser(anyString)) .thenReturn("failure"); String newUsername = "newusername"; // Act cut.methodToTest(newUsername); // Assert // Should throw exception and be checked with the // expected parameter in test } </code>
// test the exception
@Test(expected = Exception.class)
public void registerUser_ThrowExceptionOnError() {
    // Arrange
    when(mockedConnector.getService())
        .thenReturn(mockedService);
    // return failure on any string
    when(mockedService.registerUser(anyString))
        .thenReturn("failure");
    String newUsername = "newusername";

    // Act
    cut.methodToTest(newUsername);

    // Assert
    // Should throw exception and be checked with the
    // expected parameter in test
}

Hope this helps you out.

0

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật